diff options
author | Steve Grubb <sgrubb@redhat.com> | 2006-04-02 17:07:33 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2006-05-01 06:10:04 -0400 |
commit | 073115d6b29c7910feaa08241c6484637f5ca958 (patch) | |
tree | 5fd32da9f54b3c12b65d3c0142fb9bdf87dc01c3 | |
parent | ce29b682e228c70cdc91a1b2935c5adb2087bab8 (diff) |
[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>
-rw-r--r-- | include/linux/audit.h | 7 | ||||
-rw-r--r-- | ipc/msg.c | 11 | ||||
-rw-r--r-- | ipc/sem.c | 11 | ||||
-rw-r--r-- | ipc/shm.c | 19 | ||||
-rw-r--r-- | ipc/util.c | 7 | ||||
-rw-r--r-- | kernel/auditsc.c | 54 |
6 files changed, 98 insertions, 11 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index d5c40823e166..b74c148f14e3 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -83,6 +83,7 @@ | |||
83 | #define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */ | 83 | #define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */ |
84 | #define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */ | 84 | #define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */ |
85 | #define AUDIT_CWD 1307 /* Current working directory */ | 85 | #define AUDIT_CWD 1307 /* Current working directory */ |
86 | #define AUDIT_IPC_SET_PERM 1311 /* IPC new permissions record type */ | ||
86 | 87 | ||
87 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 88 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
88 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 89 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
@@ -319,7 +320,8 @@ extern void auditsc_get_stamp(struct audit_context *ctx, | |||
319 | struct timespec *t, unsigned int *serial); | 320 | struct timespec *t, unsigned int *serial); |
320 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); | 321 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); |
321 | extern uid_t audit_get_loginuid(struct audit_context *ctx); | 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 | extern int audit_socketcall(int nargs, unsigned long *args); | 325 | extern int audit_socketcall(int nargs, unsigned long *args); |
324 | extern int audit_sockaddr(int len, void *addr); | 326 | extern int audit_sockaddr(int len, void *addr); |
325 | extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); | 327 | extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); |
@@ -338,7 +340,8 @@ extern int audit_set_macxattr(const char *name); | |||
338 | #define audit_inode_child(d,i,p) do { ; } while (0) | 340 | #define audit_inode_child(d,i,p) do { ; } while (0) |
339 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) | 341 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) |
340 | #define audit_get_loginuid(c) ({ -1; }) | 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 | #define audit_socketcall(n,a) ({ 0; }) | 345 | #define audit_socketcall(n,a) ({ 0; }) |
343 | #define audit_sockaddr(len, addr) ({ 0; }) | 346 | #define audit_sockaddr(len, addr) ({ 0; }) |
344 | #define audit_avc_path(dentry, mnt) ({ 0; }) | 347 | #define audit_avc_path(dentry, mnt) ({ 0; }) |
@@ -13,6 +13,9 @@ | |||
13 | * mostly rewritten, threaded and wake-one semantics added | 13 | * mostly rewritten, threaded and wake-one semantics added |
14 | * MSGMAX limit removed, sysctl's added | 14 | * MSGMAX limit removed, sysctl's added |
15 | * (c) 1999 Manfred Spraul <manfred@colorfullife.com> | 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 | #include <linux/capability.h> | 21 | #include <linux/capability.h> |
@@ -447,6 +450,11 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) | |||
447 | if (msg_checkid(msq,msqid)) | 450 | if (msg_checkid(msq,msqid)) |
448 | goto out_unlock_up; | 451 | goto out_unlock_up; |
449 | ipcp = &msq->q_perm; | 452 | ipcp = &msq->q_perm; |
453 | |||
454 | err = audit_ipc_obj(ipcp); | ||
455 | if (err) | ||
456 | goto out_unlock_up; | ||
457 | |||
450 | err = -EPERM; | 458 | err = -EPERM; |
451 | if (current->euid != ipcp->cuid && | 459 | if (current->euid != ipcp->cuid && |
452 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) | 460 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) |
@@ -460,7 +468,8 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) | |||
460 | switch (cmd) { | 468 | switch (cmd) { |
461 | case IPC_SET: | 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 | goto out_unlock_up; | 473 | goto out_unlock_up; |
465 | 474 | ||
466 | err = -EPERM; | 475 | err = -EPERM; |
@@ -61,6 +61,9 @@ | |||
61 | * (c) 2001 Red Hat Inc <alan@redhat.com> | 61 | * (c) 2001 Red Hat Inc <alan@redhat.com> |
62 | * Lockless wakeup | 62 | * Lockless wakeup |
63 | * (c) 2003 Manfred Spraul <manfred@colorfullife.com> | 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 | #include <linux/config.h> | 69 | #include <linux/config.h> |
@@ -820,6 +823,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
820 | goto out_unlock; | 823 | goto out_unlock; |
821 | } | 824 | } |
822 | ipcp = &sma->sem_perm; | 825 | ipcp = &sma->sem_perm; |
826 | |||
827 | err = audit_ipc_obj(ipcp); | ||
828 | if (err) | ||
829 | goto out_unlock; | ||
830 | |||
823 | if (current->euid != ipcp->cuid && | 831 | if (current->euid != ipcp->cuid && |
824 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { | 832 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { |
825 | err=-EPERM; | 833 | err=-EPERM; |
@@ -836,7 +844,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
836 | err = 0; | 844 | err = 0; |
837 | break; | 845 | break; |
838 | case IPC_SET: | 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 | goto out_unlock; | 849 | goto out_unlock; |
841 | ipcp->uid = setbuf.uid; | 850 | ipcp->uid = setbuf.uid; |
842 | ipcp->gid = setbuf.gid; | 851 | ipcp->gid = setbuf.gid; |
@@ -13,6 +13,8 @@ | |||
13 | * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com> | 13 | * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com> |
14 | * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com> | 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 | #include <linux/config.h> | 20 | #include <linux/config.h> |
@@ -542,6 +544,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
542 | if(err) | 544 | if(err) |
543 | goto out_unlock; | 545 | goto out_unlock; |
544 | 546 | ||
547 | err = audit_ipc_obj(&(shp->shm_perm)); | ||
548 | if (err) | ||
549 | goto out_unlock; | ||
550 | |||
545 | if (!capable(CAP_IPC_LOCK)) { | 551 | if (!capable(CAP_IPC_LOCK)) { |
546 | err = -EPERM; | 552 | err = -EPERM; |
547 | if (current->euid != shp->shm_perm.uid && | 553 | if (current->euid != shp->shm_perm.uid && |
@@ -594,6 +600,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
594 | if(err) | 600 | if(err) |
595 | goto out_unlock_up; | 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 | if (current->euid != shp->shm_perm.uid && | 607 | if (current->euid != shp->shm_perm.uid && |
598 | current->euid != shp->shm_perm.cuid && | 608 | current->euid != shp->shm_perm.cuid && |
599 | !capable(CAP_SYS_ADMIN)) { | 609 | !capable(CAP_SYS_ADMIN)) { |
@@ -627,12 +637,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
627 | err=-EINVAL; | 637 | err=-EINVAL; |
628 | if(shp==NULL) | 638 | if(shp==NULL) |
629 | goto out_up; | 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 | err = shm_checkid(shp,shmid); | 640 | err = shm_checkid(shp,shmid); |
634 | if(err) | 641 | if(err) |
635 | goto out_unlock_up; | 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) | ||
648 | goto out_unlock_up; | ||
636 | err=-EPERM; | 649 | err=-EPERM; |
637 | if (current->euid != shp->shm_perm.uid && | 650 | if (current->euid != shp->shm_perm.uid && |
638 | current->euid != shp->shm_perm.cuid && | 651 | current->euid != shp->shm_perm.cuid && |
diff --git a/ipc/util.c b/ipc/util.c index b3dcfad3b4f7..8193299f45f6 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -10,6 +10,8 @@ | |||
10 | * Manfred Spraul <manfred@colorfullife.com> | 10 | * Manfred Spraul <manfred@colorfullife.com> |
11 | * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary(). | 11 | * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary(). |
12 | * Mingming Cao <cmm@us.ibm.com> | 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 | #include <linux/config.h> | 17 | #include <linux/config.h> |
@@ -27,6 +29,7 @@ | |||
27 | #include <linux/workqueue.h> | 29 | #include <linux/workqueue.h> |
28 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
29 | #include <linux/proc_fs.h> | 31 | #include <linux/proc_fs.h> |
32 | #include <linux/audit.h> | ||
30 | 33 | ||
31 | #include <asm/unistd.h> | 34 | #include <asm/unistd.h> |
32 | 35 | ||
@@ -464,8 +467,10 @@ void ipc_rcu_putref(void *ptr) | |||
464 | 467 | ||
465 | int ipcperms (struct kern_ipc_perm *ipcp, short flag) | 468 | int ipcperms (struct kern_ipc_perm *ipcp, short flag) |
466 | { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ | 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 | requested_mode = (flag >> 6) | (flag >> 3) | flag; | 474 | requested_mode = (flag >> 6) | (flag >> 3) | flag; |
470 | granted_mode = ipcp->mode; | 475 | granted_mode = ipcp->mode; |
471 | if (current->euid == ipcp->cuid || current->euid == ipcp->uid) | 476 | if (current->euid == ipcp->cuid || current->euid == ipcp->uid) |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index d94e0404113c..a300736ee037 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -646,6 +646,25 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
646 | } | 646 | } |
647 | break; } | 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 | case AUDIT_SOCKETCALL: { | 668 | case AUDIT_SOCKETCALL: { |
650 | int i; | 669 | int i; |
651 | struct audit_aux_data_socketcall *axs = (void *)aux; | 670 | struct audit_aux_data_socketcall *axs = (void *)aux; |
@@ -1148,7 +1167,36 @@ uid_t audit_get_loginuid(struct audit_context *ctx) | |||
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 | * @qbytes: msgq bytes | 1200 | * @qbytes: msgq bytes |
1153 | * @uid: msgq user id | 1201 | * @uid: msgq user id |
1154 | * @gid: msgq group id | 1202 | * @gid: msgq group id |
@@ -1156,7 +1204,7 @@ uid_t audit_get_loginuid(struct audit_context *ctx) | |||
1156 | * | 1204 | * |
1157 | * Returns 0 for success or NULL context or < 0 on error. | 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 | struct audit_aux_data_ipcctl *ax; | 1209 | struct audit_aux_data_ipcctl *ax; |
1162 | struct audit_context *context = current->audit_context; | 1210 | struct audit_context *context = current->audit_context; |
@@ -1174,7 +1222,7 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, str | |||
1174 | ax->mode = mode; | 1222 | ax->mode = mode; |
1175 | selinux_get_ipc_sid(ipcp, &ax->osid); | 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 | ax->d.next = context->aux; | 1226 | ax->d.next = context->aux; |
1179 | context->aux = (void *)ax; | 1227 | context->aux = (void *)ax; |
1180 | return 0; | 1228 | return 0; |