Here's an untested first attempt at auditing msgctl, semctl and shmctl
IPC_SET calls. It should print the requested uid, gid, mod and qbytes
values.
We keep a linked list in the audit context, which can be extended to
contain other types of information than the IPC_SET info we add here. I
haven't added any locking -- am I right in thinking that we don't
actually need any?
--- linux-2.6.9/kernel/auditsc.c~ 2005-01-31 13:22:07.000000000 +0000
+++ linux-2.6.9/kernel/auditsc.c 2005-02-01 17:33:59.201084736 +0000
@@ -98,6 +98,23 @@ struct audit_names {
dev_t rdev;
};
+struct audit_aux_data {
+ struct audit_aux_data *next;
+ int type;
+};
+
+#define AUDIT_AUX_IPCPERM 0
+
+struct audit_aux_data_ipcctl {
+ struct audit_aux_data d;
+ struct ipc_perm p;
+ unsigned long qbytes;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+};
+
+
/* The per-task audit context. */
struct audit_context {
int in_syscall; /* 1 if task is in a syscall */
@@ -113,6 +130,7 @@ struct audit_context {
int name_count;
struct audit_names names[AUDIT_NAMES];
struct audit_context *previous; /* For nested syscalls */
+ struct audit_aux_data *aux;
/* Save things to print about task_struct */
pid_t pid;
@@ -560,6 +578,16 @@ static inline void audit_free_files(stru
}
}
+static inline void audit_free_aux(struct audit_context *context)
+{
+ struct audit_aux_data *aux;
+
+ while ((aux = context->aux)) {
+ context->aux = aux;
+ kfree(aux);
+ }
+}
+
static inline void audit_zero_context(struct audit_context *context,
enum audit_state state)
{
@@ -628,6 +656,7 @@ static inline void audit_free_context(st
}
audit_free_names(context);
audit_free_files(context);
+ audit_free_aux(context);
kfree(context);
context = previous;
} while (context);
@@ -666,6 +695,29 @@ static void audit_log_exit(struct audit_
context->euid, context->suid, context->fsuid,
context->egid, context->sgid, context->fsgid);
audit_log_end(ab);
+ while (context->aux) {
+ struct audit_aux_data *aux;
+
+ ab = audit_log_start(context);
+ if (!ab)
+ continue; /* audit_panic has been called */
+
+ aux = context->aux;
+ context->aux = aux->next;
+
+ audit_log_format(ab, "auxitem=%d", aux->type);
+ switch (aux->type) {
+ case AUDIT_AUX_IPCPERM: {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ audit_log_format(ab,
+ " qbytes=%lx uid=%d gid=%d mode=%x",
+ axi->qbytes, axi->uid, axi->gid, axi->mode);
+ }
+ }
+ audit_log_end(ab);
+ kfree(aux);
+ }
+
for (i = 0; i < context->name_count; i++) {
ab = audit_log_start(context);
if (!ab)
@@ -867,6 +919,7 @@ void audit_syscall_exit(struct task_stru
} else {
audit_free_names(context);
audit_free_files(context);
+ audit_free_aux(context);
audit_zero_context(context, context->state);
tsk->audit_context = context;
}
@@ -1049,3 +1102,26 @@ int audit_notify_watch(struct inode *ino
return 0;
}
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+{
+ struct audit_aux_data_ipcctl *ax;
+ struct audit_context *context = current->audit_context;
+
+ if (likely(!context))
+ return 0;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->qbytes = qbytes;
+ ax->uid = uid;
+ ax->gid = gid;
+ ax->mode = mode;
+
+ ax->d.type = AUDIT_AUX_IPCPERM;
+ ax->d.next = context->aux; /* Do we need locking? Can anyone else walk this list
*/
+ context->aux = ax->d.next; /* while we're mucking about with it? I think not.
dwmw2 */
+
+ return 0;
+}
--- linux-2.6.9/ipc/msg.c~ 2004-10-18 22:53:06.000000000 +0100
+++ linux-2.6.9/ipc/msg.c 2005-02-01 17:28:28.155088688 +0000
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/security.h>
#include <linux/sched.h>
+#include <linux/audit.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -424,6 +425,8 @@ asmlinkage long sys_msgctl (int msqid, i
return -EFAULT;
if (copy_msqid_from_user (&setbuf, buf, version))
return -EFAULT;
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
+ return err;
break;
case IPC_RMID:
break;
--- linux-2.6.9/ipc/sem.c~ 2004-10-18 22:53:50.000000000 +0100
+++ linux-2.6.9/ipc/sem.c 2005-02-01 17:28:32.748056160 +0000
@@ -71,6 +71,7 @@
#include <linux/time.h>
#include <linux/smp_lock.h>
#include <linux/security.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -788,6 +789,8 @@ static int semctl_down(int semid, int se
if(cmd == IPC_SET) {
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
+ return err;
}
sma = sem_lock(semid);
if(sma==NULL)
--- linux-2.6.9/ipc/shm.c~ 2004-10-18 22:54:08.000000000 +0100
+++ linux-2.6.9/ipc/shm.c 2005-02-01 17:28:36.766111032 +0000
@@ -26,6 +26,7 @@
#include <linux/proc_fs.h>
#include <linux/shmem_fs.h>
#include <linux/security.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -594,6 +595,8 @@ asmlinkage long sys_shmctl (int shmid, i
err = -EFAULT;
goto out;
}
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
+ return err;
down(&shm_ids.sem);
shp = shm_lock(shmid);
err=-EINVAL;
--- linux-2.6.9/include/linux/audit.h~ 2005-01-31 13:22:07.000000000 +0000
+++ linux-2.6.9/include/linux/audit.h 2005-02-01 16:45:38.011083672 +0000
@@ -179,6 +179,7 @@ extern void audit_get_stamp(struct audit
extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
extern int audit_notify_watch(struct inode *inode, int mask);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -189,6 +190,7 @@ extern int audit_notify_watch(struct ino
#define audit_inode(n,i,d) do { ; } while (0)
#define audit_get_loginuid(c) ({ -1; })
#define audit_notify_watch(t,i,m) ({ 0; })
+#define audit_ipc_perms(q, u, g, m) do ({ 0; })
#endif
--
dwmw2