[PATCH] Audit permission changes on IPC objects.

From: David Woodhouse
Date: Mon Feb 28 2005 - 08:59:06 EST


Capture the requested permissions on IPC_SET calls. We do this with a
hook in ipc/{sem,shm,msg}.c for two reasons. Firstly, it would require a
lot of arch-specific knowledge about syscall numbers and sys_ipc()
multiplexing to get at this information from syscall_trace_enter().
Secondly, if we did it there it could be changed by the time the IPC
code does copy_from_user() to fetch it again.

Signed-off-by: David Woodhouse <dwmw2@xxxxxxxxxxxxx>

===== include/linux/audit.h 1.2 vs edited =====
--- 1.2/include/linux/audit.h 2005-01-31 06:33:47 +00:00
+++ edited/include/linux/audit.h 2005-02-28 13:39:05 +00:00
@@ -150,6 +150,7 @@
struct timespec *t, int *serial);
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_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)
@@ -159,6 +160,7 @@
#define audit_putname(n) do { ; } while (0)
#define audit_inode(n,i,d) do { ; } while (0)
#define audit_get_loginuid(c) ({ -1; })
+#define audit_ipc_perms(q,u,g,m) ({ 0; })
#endif

#ifdef CONFIG_AUDIT
===== ipc/msg.c 1.24 vs edited =====
--- 1.24/ipc/msg.c 2004-10-28 08:39:57 +01:00
+++ edited/ipc/msg.c 2005-02-28 13:39:42 +00:00
@@ -25,6 +25,7 @@
#include <linux/security.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
+#include <linux/audit.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -425,6 +426,8 @@
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;
===== ipc/sem.c 1.36 vs edited =====
--- 1.36/ipc/sem.c 2005-01-05 02:48:17 +00:00
+++ edited/ipc/sem.c 2005-02-28 13:39:48 +00:00
@@ -72,6 +72,7 @@
#include <linux/smp_lock.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include "util.h"

@@ -803,6 +804,8 @@
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)
===== ipc/shm.c 1.43 vs edited =====
--- 1.43/ipc/shm.c 2004-12-13 10:47:27 +00:00
+++ edited/ipc/shm.c 2005-02-28 13:39:28 +00:00
@@ -27,6 +27,7 @@
#include <linux/shmem_fs.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>

#include "util.h"
@@ -600,6 +601,8 @@
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;
===== kernel/auditsc.c 1.6 vs edited =====
--- 1.6/kernel/auditsc.c 2005-01-31 06:33:47 +00:00
+++ edited/kernel/auditsc.c 2005-02-28 13:43:01 +00:00
@@ -92,6 +92,23 @@
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 */
@@ -107,6 +124,7 @@
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;
@@ -504,6 +522,16 @@
context->name_count = 0;
}

+static inline void audit_free_aux(struct audit_context *context)
+{
+ struct audit_aux_data *aux;
+
+ while ((aux = context->aux)) {
+ context->aux = aux->next;
+ kfree(aux);
+ }
+}
+
static inline void audit_zero_context(struct audit_context *context,
enum audit_state state)
{
@@ -570,6 +598,7 @@
context->name_count, count);
}
audit_free_names(context);
+ audit_free_aux(context);
kfree(context);
context = previous;
} while (context);
@@ -607,6 +636,29 @@
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)
@@ -789,6 +841,7 @@
tsk->audit_context = new_context;
} else {
audit_free_names(context);
+ audit_free_aux(context);
audit_zero_context(context, context->state);
tsk->audit_context = context;
}
@@ -926,4 +979,30 @@
uid_t audit_get_loginuid(struct audit_context *ctx)
{
return ctx ? ctx->loginuid : -1;
+}
+
+ 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;
+ context->aux = (void *)ax;
+ return 0;
}
A

6 (

x 9
z




z



z
raph

z


?
?


z


z

5





n
6

?

y c li?
!
50,?
6

9

?
6
0)
z

ph



?



0,?
6?
?
6


?


6!

,?
6

z


ph?
9

z

y

?


A













y


ph

y c li?

y

?
50y


y c link




h

y c link

x 
?
?


!
0,?
6


y
y


ph
ph




y

y

aph


y c link

ph


?

h


h
'

aph



y c link






t


h


h





y c link








W ÿ
)Y ¡
x 

x ?
h
?

Òn A







6


6



pc/msg.?

x c link
8?x 
s
ne !
?
6
0,?
6

05




6
?8
05

?
50,?
6

--
dwmw2

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/