Commit 073115d6b29c7910feaa08241c6484637f5ca958

Authored by Steve Grubb
Committed by Al Viro
1 parent ce29b682e2

[PATCH] Rework of IPC auditing

1) The audit_ipc_perms() function has been split into two different
functions:
        - audit_ipc_obj()
        - audit_ipc_set_perm()

There's a key shift here...  The audit_ipc_obj() collects the uid, gid,
mode, and SElinux context label of the current ipc object.  This
audit_ipc_obj() hook is now found in several places.  Most notably, it
is hooked in ipcperms(), which is called in various places around the
ipc code permforming a MAC check.  Additionally there are several places
where *checkid() is used to validate that an operation is being
performed on a valid object while not necessarily having a nearby
ipcperms() call.  In these locations, audit_ipc_obj() is called to
ensure that the information is captured by the audit system.

The audit_set_new_perm() function is called any time the permissions on
the ipc object changes.  In this case, the NEW permissions are recorded
(and note that an audit_ipc_obj() call exists just a few lines before
each instance).

2) Support for an AUDIT_IPC_SET_PERM audit message type.  This allows
for separate auxiliary audit records for normal operations on an IPC
object and permissions changes.  Note that the same struct
audit_aux_data_ipcctl is used and populated, however there are separate
audit_log_format statements based on the type of the message.  Finally,
the AUDIT_IPC block of code in audit_free_aux() was extended to handle
aux messages of this new type.  No more mem leaks I hope ;-)

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 6 changed files with 98 additions and 11 deletions Side-by-side Diff

include/linux/audit.h
... ... @@ -83,6 +83,7 @@
83 83 #define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
84 84 #define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
85 85 #define AUDIT_CWD 1307 /* Current working directory */
  86 +#define AUDIT_IPC_SET_PERM 1311 /* IPC new permissions record type */
86 87  
87 88 #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
88 89 #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
... ... @@ -319,7 +320,8 @@
319 320 struct timespec *t, unsigned int *serial);
320 321 extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
321 322 extern uid_t audit_get_loginuid(struct audit_context *ctx);
322   -extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
  323 +extern int audit_ipc_obj(struct kern_ipc_perm *ipcp);
  324 +extern int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
323 325 extern int audit_socketcall(int nargs, unsigned long *args);
324 326 extern int audit_sockaddr(int len, void *addr);
325 327 extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
... ... @@ -338,7 +340,8 @@
338 340 #define audit_inode_child(d,i,p) do { ; } while (0)
339 341 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
340 342 #define audit_get_loginuid(c) ({ -1; })
341   -#define audit_ipc_perms(q,u,g,m,i) ({ 0; })
  343 +#define audit_ipc_obj(i) ({ 0; })
  344 +#define audit_ipc_set_perm(q,u,g,m,i) ({ 0; })
342 345 #define audit_socketcall(n,a) ({ 0; })
343 346 #define audit_sockaddr(len, addr) ({ 0; })
344 347 #define audit_avc_path(dentry, mnt) ({ 0; })
... ... @@ -13,6 +13,9 @@
13 13 * mostly rewritten, threaded and wake-one semantics added
14 14 * MSGMAX limit removed, sysctl's added
15 15 * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
  16 + *
  17 + * support for audit of ipc object properties and permission changes
  18 + * Dustin Kirkland <dustin.kirkland@us.ibm.com>
16 19 */
17 20  
18 21 #include <linux/capability.h>
... ... @@ -447,6 +450,11 @@
447 450 if (msg_checkid(msq,msqid))
448 451 goto out_unlock_up;
449 452 ipcp = &msq->q_perm;
  453 +
  454 + err = audit_ipc_obj(ipcp);
  455 + if (err)
  456 + goto out_unlock_up;
  457 +
450 458 err = -EPERM;
451 459 if (current->euid != ipcp->cuid &&
452 460 current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
... ... @@ -460,7 +468,8 @@
460 468 switch (cmd) {
461 469 case IPC_SET:
462 470 {
463   - if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
  471 + err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
  472 + if (err)
464 473 goto out_unlock_up;
465 474  
466 475 err = -EPERM;
... ... @@ -61,6 +61,9 @@
61 61 * (c) 2001 Red Hat Inc <alan@redhat.com>
62 62 * Lockless wakeup
63 63 * (c) 2003 Manfred Spraul <manfred@colorfullife.com>
  64 + *
  65 + * support for audit of ipc object properties and permission changes
  66 + * Dustin Kirkland <dustin.kirkland@us.ibm.com>
64 67 */
65 68  
66 69 #include <linux/config.h>
... ... @@ -820,6 +823,11 @@
820 823 goto out_unlock;
821 824 }
822 825 ipcp = &sma->sem_perm;
  826 +
  827 + err = audit_ipc_obj(ipcp);
  828 + if (err)
  829 + goto out_unlock;
  830 +
823 831 if (current->euid != ipcp->cuid &&
824 832 current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
825 833 err=-EPERM;
... ... @@ -836,7 +844,8 @@
836 844 err = 0;
837 845 break;
838 846 case IPC_SET:
839   - if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
  847 + err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
  848 + if (err)
840 849 goto out_unlock;
841 850 ipcp->uid = setbuf.uid;
842 851 ipcp->gid = setbuf.gid;
... ... @@ -13,6 +13,8 @@
13 13 * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
14 14 * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
15 15 *
  16 + * support for audit of ipc object properties and permission changes
  17 + * Dustin Kirkland <dustin.kirkland@us.ibm.com>
16 18 */
17 19  
18 20 #include <linux/config.h>
... ... @@ -542,6 +544,10 @@
542 544 if(err)
543 545 goto out_unlock;
544 546  
  547 + err = audit_ipc_obj(&(shp->shm_perm));
  548 + if (err)
  549 + goto out_unlock;
  550 +
545 551 if (!capable(CAP_IPC_LOCK)) {
546 552 err = -EPERM;
547 553 if (current->euid != shp->shm_perm.uid &&
... ... @@ -594,6 +600,10 @@
594 600 if(err)
595 601 goto out_unlock_up;
596 602  
  603 + err = audit_ipc_obj(&(shp->shm_perm));
  604 + if (err)
  605 + goto out_unlock_up;
  606 +
597 607 if (current->euid != shp->shm_perm.uid &&
598 608 current->euid != shp->shm_perm.cuid &&
599 609 !capable(CAP_SYS_ADMIN)) {
600 610  
... ... @@ -627,11 +637,14 @@
627 637 err=-EINVAL;
628 638 if(shp==NULL)
629 639 goto out_up;
630   - if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid,
631   - setbuf.mode, &(shp->shm_perm))))
632   - goto out_unlock_up;
633 640 err = shm_checkid(shp,shmid);
634 641 if(err)
  642 + goto out_unlock_up;
  643 + err = audit_ipc_obj(&(shp->shm_perm));
  644 + if (err)
  645 + goto out_unlock_up;
  646 + err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm));
  647 + if (err)
635 648 goto out_unlock_up;
636 649 err=-EPERM;
637 650 if (current->euid != shp->shm_perm.uid &&
... ... @@ -10,6 +10,8 @@
10 10 * Manfred Spraul <manfred@colorfullife.com>
11 11 * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
12 12 * Mingming Cao <cmm@us.ibm.com>
  13 + * Mar 2006 - support for audit of ipc object properties
  14 + * Dustin Kirkland <dustin.kirkland@us.ibm.com>
13 15 */
14 16  
15 17 #include <linux/config.h>
... ... @@ -27,6 +29,7 @@
27 29 #include <linux/workqueue.h>
28 30 #include <linux/seq_file.h>
29 31 #include <linux/proc_fs.h>
  32 +#include <linux/audit.h>
30 33  
31 34 #include <asm/unistd.h>
32 35  
33 36  
... ... @@ -464,8 +467,10 @@
464 467  
465 468 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
466 469 { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
467   - int requested_mode, granted_mode;
  470 + int requested_mode, granted_mode, err;
468 471  
  472 + if (unlikely((err = audit_ipc_obj(ipcp))))
  473 + return err;
469 474 requested_mode = (flag >> 6) | (flag >> 3) | flag;
470 475 granted_mode = ipcp->mode;
471 476 if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
... ... @@ -646,6 +646,25 @@
646 646 }
647 647 break; }
648 648  
  649 + case AUDIT_IPC_SET_PERM: {
  650 + struct audit_aux_data_ipcctl *axi = (void *)aux;
  651 + audit_log_format(ab,
  652 + " new qbytes=%lx new iuid=%u new igid=%u new mode=%x",
  653 + axi->qbytes, axi->uid, axi->gid, axi->mode);
  654 + if (axi->osid != 0) {
  655 + char *ctx = NULL;
  656 + u32 len;
  657 + if (selinux_ctxid_to_string(
  658 + axi->osid, &ctx, &len)) {
  659 + audit_log_format(ab, " osid=%u",
  660 + axi->osid);
  661 + call_panic = 1;
  662 + } else
  663 + audit_log_format(ab, " obj=%s", ctx);
  664 + kfree(ctx);
  665 + }
  666 + break; }
  667 +
649 668 case AUDIT_SOCKETCALL: {
650 669 int i;
651 670 struct audit_aux_data_socketcall *axs = (void *)aux;
... ... @@ -1148,7 +1167,36 @@
1148 1167 }
1149 1168  
1150 1169 /**
1151   - * audit_ipc_perms - record audit data for ipc
  1170 + * audit_ipc_obj - record audit data for ipc object
  1171 + * @ipcp: ipc permissions
  1172 + *
  1173 + * Returns 0 for success or NULL context or < 0 on error.
  1174 + */
  1175 +int audit_ipc_obj(struct kern_ipc_perm *ipcp)
  1176 +{
  1177 + struct audit_aux_data_ipcctl *ax;
  1178 + struct audit_context *context = current->audit_context;
  1179 +
  1180 + if (likely(!context))
  1181 + return 0;
  1182 +
  1183 + ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
  1184 + if (!ax)
  1185 + return -ENOMEM;
  1186 +
  1187 + ax->uid = ipcp->uid;
  1188 + ax->gid = ipcp->gid;
  1189 + ax->mode = ipcp->mode;
  1190 + selinux_get_ipc_sid(ipcp, &ax->osid);
  1191 +
  1192 + ax->d.type = AUDIT_IPC;
  1193 + ax->d.next = context->aux;
  1194 + context->aux = (void *)ax;
  1195 + return 0;
  1196 +}
  1197 +
  1198 +/**
  1199 + * audit_ipc_set_perm - record audit data for new ipc permissions
1152 1200 * @qbytes: msgq bytes
1153 1201 * @uid: msgq user id
1154 1202 * @gid: msgq group id
... ... @@ -1156,7 +1204,7 @@
1156 1204 *
1157 1205 * Returns 0 for success or NULL context or < 0 on error.
1158 1206 */
1159   -int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
  1207 +int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
1160 1208 {
1161 1209 struct audit_aux_data_ipcctl *ax;
1162 1210 struct audit_context *context = current->audit_context;
... ... @@ -1174,7 +1222,7 @@
1174 1222 ax->mode = mode;
1175 1223 selinux_get_ipc_sid(ipcp, &ax->osid);
1176 1224  
1177   - ax->d.type = AUDIT_IPC;
  1225 + ax->d.type = AUDIT_IPC_SET_PERM;
1178 1226 ax->d.next = context->aux;
1179 1227 context->aux = (void *)ax;
1180 1228 return 0;