diff options
author | Dustin Kirkland <dustin.kirkland@us.ibm.com> | 2005-11-03 12:15:16 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2006-03-20 14:08:54 -0500 |
commit | 8c8570fb8feef2bc166bee75a85748b25cda22d9 (patch) | |
tree | ed783d405ea9d5f3d3ccc57fb56c7b7cb2cdfb82 | |
parent | c8edc80c8b8c397c53f4f659a05b9ea6208029bf (diff) |
[PATCH] Capture selinux subject/object context information.
This patch extends existing audit records with subject/object context
information. Audit records associated with filesystem inodes, ipc, and
tasks now contain SELinux label information in the field "subj" if the
item is performing the action, or in "obj" if the item is the receiver
of an action.
These labels are collected via hooks in SELinux and appended to the
appropriate record in the audit code.
This additional information is required for Common Criteria Labeled
Security Protection Profile (LSPP).
[AV: fixed kmalloc flags use]
[folded leak fixes]
[folded cleanup from akpm (kfree(NULL)]
[folded audit_inode_context() leak fix]
[folded akpm's fix for audit_ipc_perm() definition in case of !CONFIG_AUDIT]
Signed-off-by: Dustin Kirkland <dustin.kirkland@us.ibm.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | include/linux/audit.h | 8 | ||||
-rw-r--r-- | include/linux/security.h | 27 | ||||
-rw-r--r-- | ipc/msg.c | 5 | ||||
-rw-r--r-- | ipc/sem.c | 5 | ||||
-rw-r--r-- | ipc/shm.c | 4 | ||||
-rw-r--r-- | kernel/audit.c | 2 | ||||
-rw-r--r-- | kernel/auditsc.c | 142 | ||||
-rw-r--r-- | security/dummy.c | 6 | ||||
-rw-r--r-- | security/selinux/hooks.c | 96 |
9 files changed, 226 insertions, 69 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 8fa1a8fbc04..1912d8e8ae9 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -285,13 +285,14 @@ extern void auditsc_get_stamp(struct audit_context *ctx, | |||
285 | struct timespec *t, unsigned int *serial); | 285 | struct timespec *t, unsigned int *serial); |
286 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); | 286 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); |
287 | extern uid_t audit_get_loginuid(struct audit_context *ctx); | 287 | extern uid_t audit_get_loginuid(struct audit_context *ctx); |
288 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); | 288 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp); |
289 | extern int audit_socketcall(int nargs, unsigned long *args); | 289 | extern int audit_socketcall(int nargs, unsigned long *args); |
290 | extern int audit_sockaddr(int len, void *addr); | 290 | extern int audit_sockaddr(int len, void *addr); |
291 | extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); | 291 | extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); |
292 | extern void audit_signal_info(int sig, struct task_struct *t); | 292 | extern void audit_signal_info(int sig, struct task_struct *t); |
293 | extern int audit_filter_user(struct netlink_skb_parms *cb, int type); | 293 | extern int audit_filter_user(struct netlink_skb_parms *cb, int type); |
294 | extern int audit_filter_type(int type); | 294 | extern int audit_filter_type(int type); |
295 | extern int audit_set_macxattr(const char *name); | ||
295 | #else | 296 | #else |
296 | #define audit_alloc(t) ({ 0; }) | 297 | #define audit_alloc(t) ({ 0; }) |
297 | #define audit_free(t) do { ; } while (0) | 298 | #define audit_free(t) do { ; } while (0) |
@@ -306,12 +307,13 @@ extern int audit_filter_type(int type); | |||
306 | #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) | 307 | #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) |
307 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) | 308 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) |
308 | #define audit_get_loginuid(c) ({ -1; }) | 309 | #define audit_get_loginuid(c) ({ -1; }) |
309 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) | 310 | #define audit_ipc_perms(q,u,g,m,i) ({ 0; }) |
310 | #define audit_socketcall(n,a) ({ 0; }) | 311 | #define audit_socketcall(n,a) ({ 0; }) |
311 | #define audit_sockaddr(len, addr) ({ 0; }) | 312 | #define audit_sockaddr(len, addr) ({ 0; }) |
312 | #define audit_avc_path(dentry, mnt) ({ 0; }) | 313 | #define audit_avc_path(dentry, mnt) ({ 0; }) |
313 | #define audit_signal_info(s,t) do { ; } while (0) | 314 | #define audit_signal_info(s,t) do { ; } while (0) |
314 | #define audit_filter_user(cb,t) ({ 1; }) | 315 | #define audit_filter_user(cb,t) ({ 1; }) |
316 | #define audit_set_macxattr(n) do { ; } while (0) | ||
315 | #endif | 317 | #endif |
316 | 318 | ||
317 | #ifdef CONFIG_AUDIT | 319 | #ifdef CONFIG_AUDIT |
@@ -340,6 +342,7 @@ extern void audit_send_reply(int pid, int seq, int type, | |||
340 | int done, int multi, | 342 | int done, int multi, |
341 | void *payload, int size); | 343 | void *payload, int size); |
342 | extern void audit_log_lost(const char *message); | 344 | extern void audit_log_lost(const char *message); |
345 | extern void audit_panic(const char *message); | ||
343 | extern struct semaphore audit_netlink_sem; | 346 | extern struct semaphore audit_netlink_sem; |
344 | #else | 347 | #else |
345 | #define audit_log(c,g,t,f,...) do { ; } while (0) | 348 | #define audit_log(c,g,t,f,...) do { ; } while (0) |
@@ -350,6 +353,7 @@ extern struct semaphore audit_netlink_sem; | |||
350 | #define audit_log_hex(a,b,l) do { ; } while (0) | 353 | #define audit_log_hex(a,b,l) do { ; } while (0) |
351 | #define audit_log_untrustedstring(a,s) do { ; } while (0) | 354 | #define audit_log_untrustedstring(a,s) do { ; } while (0) |
352 | #define audit_log_d_path(b,p,d,v) do { ; } while (0) | 355 | #define audit_log_d_path(b,p,d,v) do { ; } while (0) |
356 | #define audit_panic(m) do { ; } while (0) | ||
353 | #endif | 357 | #endif |
354 | #endif | 358 | #endif |
355 | #endif | 359 | #endif |
diff --git a/include/linux/security.h b/include/linux/security.h index 7cbef482e13..ec0bbbc3ffc 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -869,6 +869,11 @@ struct swap_info_struct; | |||
869 | * @ipcp contains the kernel IPC permission structure | 869 | * @ipcp contains the kernel IPC permission structure |
870 | * @flag contains the desired (requested) permission set | 870 | * @flag contains the desired (requested) permission set |
871 | * Return 0 if permission is granted. | 871 | * Return 0 if permission is granted. |
872 | * @ipc_getsecurity: | ||
873 | * Copy the security label associated with the ipc object into | ||
874 | * @buffer. @buffer may be NULL to request the size of the buffer | ||
875 | * required. @size indicates the size of @buffer in bytes. Return | ||
876 | * number of bytes used/required on success. | ||
872 | * | 877 | * |
873 | * Security hooks for individual messages held in System V IPC message queues | 878 | * Security hooks for individual messages held in System V IPC message queues |
874 | * @msg_msg_alloc_security: | 879 | * @msg_msg_alloc_security: |
@@ -1168,6 +1173,7 @@ struct security_operations { | |||
1168 | int (*inode_getxattr) (struct dentry *dentry, char *name); | 1173 | int (*inode_getxattr) (struct dentry *dentry, char *name); |
1169 | int (*inode_listxattr) (struct dentry *dentry); | 1174 | int (*inode_listxattr) (struct dentry *dentry); |
1170 | int (*inode_removexattr) (struct dentry *dentry, char *name); | 1175 | int (*inode_removexattr) (struct dentry *dentry, char *name); |
1176 | char *(*inode_xattr_getsuffix) (void); | ||
1171 | int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err); | 1177 | int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err); |
1172 | int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); | 1178 | int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); |
1173 | int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); | 1179 | int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); |
@@ -1217,6 +1223,7 @@ struct security_operations { | |||
1217 | void (*task_to_inode)(struct task_struct *p, struct inode *inode); | 1223 | void (*task_to_inode)(struct task_struct *p, struct inode *inode); |
1218 | 1224 | ||
1219 | int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag); | 1225 | int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag); |
1226 | int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size); | ||
1220 | 1227 | ||
1221 | int (*msg_msg_alloc_security) (struct msg_msg * msg); | 1228 | int (*msg_msg_alloc_security) (struct msg_msg * msg); |
1222 | void (*msg_msg_free_security) (struct msg_msg * msg); | 1229 | void (*msg_msg_free_security) (struct msg_msg * msg); |
@@ -1674,6 +1681,11 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name) | |||
1674 | return security_ops->inode_removexattr (dentry, name); | 1681 | return security_ops->inode_removexattr (dentry, name); |
1675 | } | 1682 | } |
1676 | 1683 | ||
1684 | static inline const char *security_inode_xattr_getsuffix(void) | ||
1685 | { | ||
1686 | return security_ops->inode_xattr_getsuffix(); | ||
1687 | } | ||
1688 | |||
1677 | static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) | 1689 | static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) |
1678 | { | 1690 | { |
1679 | if (unlikely (IS_PRIVATE (inode))) | 1691 | if (unlikely (IS_PRIVATE (inode))) |
@@ -1869,6 +1881,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp, | |||
1869 | return security_ops->ipc_permission (ipcp, flag); | 1881 | return security_ops->ipc_permission (ipcp, flag); |
1870 | } | 1882 | } |
1871 | 1883 | ||
1884 | static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size) | ||
1885 | { | ||
1886 | return security_ops->ipc_getsecurity(ipcp, buffer, size); | ||
1887 | } | ||
1888 | |||
1872 | static inline int security_msg_msg_alloc (struct msg_msg * msg) | 1889 | static inline int security_msg_msg_alloc (struct msg_msg * msg) |
1873 | { | 1890 | { |
1874 | return security_ops->msg_msg_alloc_security (msg); | 1891 | return security_ops->msg_msg_alloc_security (msg); |
@@ -2316,6 +2333,11 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name) | |||
2316 | return cap_inode_removexattr(dentry, name); | 2333 | return cap_inode_removexattr(dentry, name); |
2317 | } | 2334 | } |
2318 | 2335 | ||
2336 | static inline const char *security_inode_xattr_getsuffix (void) | ||
2337 | { | ||
2338 | return NULL ; | ||
2339 | } | ||
2340 | |||
2319 | static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) | 2341 | static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) |
2320 | { | 2342 | { |
2321 | return -EOPNOTSUPP; | 2343 | return -EOPNOTSUPP; |
@@ -2499,6 +2521,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp, | |||
2499 | return 0; | 2521 | return 0; |
2500 | } | 2522 | } |
2501 | 2523 | ||
2524 | static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size) | ||
2525 | { | ||
2526 | return -EOPNOTSUPP; | ||
2527 | } | ||
2528 | |||
2502 | static inline int security_msg_msg_alloc (struct msg_msg * msg) | 2529 | static inline int security_msg_msg_alloc (struct msg_msg * msg) |
2503 | { | 2530 | { |
2504 | return 0; | 2531 | return 0; |
@@ -429,8 +429,6 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) | |||
429 | return -EFAULT; | 429 | return -EFAULT; |
430 | if (copy_msqid_from_user (&setbuf, buf, version)) | 430 | if (copy_msqid_from_user (&setbuf, buf, version)) |
431 | return -EFAULT; | 431 | return -EFAULT; |
432 | if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode))) | ||
433 | return err; | ||
434 | break; | 432 | break; |
435 | case IPC_RMID: | 433 | case IPC_RMID: |
436 | break; | 434 | break; |
@@ -461,6 +459,9 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) | |||
461 | switch (cmd) { | 459 | switch (cmd) { |
462 | case IPC_SET: | 460 | case IPC_SET: |
463 | { | 461 | { |
462 | if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp))) | ||
463 | goto out_unlock_up; | ||
464 | |||
464 | err = -EPERM; | 465 | err = -EPERM; |
465 | if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) | 466 | if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) |
466 | goto out_unlock_up; | 467 | goto out_unlock_up; |
@@ -809,8 +809,6 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
809 | if(cmd == IPC_SET) { | 809 | if(cmd == IPC_SET) { |
810 | if(copy_semid_from_user (&setbuf, arg.buf, version)) | 810 | if(copy_semid_from_user (&setbuf, arg.buf, version)) |
811 | return -EFAULT; | 811 | return -EFAULT; |
812 | if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode))) | ||
813 | return err; | ||
814 | } | 812 | } |
815 | sma = sem_lock(semid); | 813 | sma = sem_lock(semid); |
816 | if(sma==NULL) | 814 | if(sma==NULL) |
@@ -821,7 +819,6 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
821 | goto out_unlock; | 819 | goto out_unlock; |
822 | } | 820 | } |
823 | ipcp = &sma->sem_perm; | 821 | ipcp = &sma->sem_perm; |
824 | |||
825 | if (current->euid != ipcp->cuid && | 822 | if (current->euid != ipcp->cuid && |
826 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { | 823 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { |
827 | err=-EPERM; | 824 | err=-EPERM; |
@@ -838,6 +835,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
838 | err = 0; | 835 | err = 0; |
839 | break; | 836 | break; |
840 | case IPC_SET: | 837 | case IPC_SET: |
838 | if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp))) | ||
839 | goto out_unlock; | ||
841 | ipcp->uid = setbuf.uid; | 840 | ipcp->uid = setbuf.uid; |
842 | ipcp->gid = setbuf.gid; | 841 | ipcp->gid = setbuf.gid; |
843 | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 842 | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
@@ -620,13 +620,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
620 | err = -EFAULT; | 620 | err = -EFAULT; |
621 | goto out; | 621 | goto out; |
622 | } | 622 | } |
623 | if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode))) | ||
624 | return err; | ||
625 | down(&shm_ids.sem); | 623 | down(&shm_ids.sem); |
626 | shp = shm_lock(shmid); | 624 | shp = shm_lock(shmid); |
627 | err=-EINVAL; | 625 | err=-EINVAL; |
628 | if(shp==NULL) | 626 | if(shp==NULL) |
629 | goto out_up; | 627 | goto out_up; |
628 | if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm)))) | ||
629 | goto out_unlock_up; | ||
630 | err = shm_checkid(shp,shmid); | 630 | err = shm_checkid(shp,shmid); |
631 | if(err) | 631 | if(err) |
632 | goto out_unlock_up; | 632 | goto out_unlock_up; |
diff --git a/kernel/audit.c b/kernel/audit.c index 1c3eb1b12bf..45c123ef77a 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -142,7 +142,7 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid) | |||
142 | nlh->nlmsg_pid = pid; | 142 | nlh->nlmsg_pid = pid; |
143 | } | 143 | } |
144 | 144 | ||
145 | static void audit_panic(const char *message) | 145 | void audit_panic(const char *message) |
146 | { | 146 | { |
147 | switch (audit_failure) | 147 | switch (audit_failure) |
148 | { | 148 | { |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 31917ac730a..4e2256ec7cf 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -34,6 +34,9 @@ | |||
34 | * | 34 | * |
35 | * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional | 35 | * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional |
36 | * filesystem information. | 36 | * filesystem information. |
37 | * | ||
38 | * Subject and object context labeling support added by <danjones@us.ibm.com> | ||
39 | * and <dustin.kirkland@us.ibm.com> for LSPP certification compliance. | ||
37 | */ | 40 | */ |
38 | 41 | ||
39 | #include <linux/init.h> | 42 | #include <linux/init.h> |
@@ -53,6 +56,7 @@ | |||
53 | #include <linux/netlink.h> | 56 | #include <linux/netlink.h> |
54 | #include <linux/compiler.h> | 57 | #include <linux/compiler.h> |
55 | #include <asm/unistd.h> | 58 | #include <asm/unistd.h> |
59 | #include <linux/security.h> | ||
56 | 60 | ||
57 | /* 0 = no checking | 61 | /* 0 = no checking |
58 | 1 = put_count checking | 62 | 1 = put_count checking |
@@ -109,6 +113,7 @@ struct audit_names { | |||
109 | uid_t uid; | 113 | uid_t uid; |
110 | gid_t gid; | 114 | gid_t gid; |
111 | dev_t rdev; | 115 | dev_t rdev; |
116 | char *ctx; | ||
112 | }; | 117 | }; |
113 | 118 | ||
114 | struct audit_aux_data { | 119 | struct audit_aux_data { |
@@ -125,6 +130,7 @@ struct audit_aux_data_ipcctl { | |||
125 | uid_t uid; | 130 | uid_t uid; |
126 | gid_t gid; | 131 | gid_t gid; |
127 | mode_t mode; | 132 | mode_t mode; |
133 | char *ctx; | ||
128 | }; | 134 | }; |
129 | 135 | ||
130 | struct audit_aux_data_socketcall { | 136 | struct audit_aux_data_socketcall { |
@@ -743,10 +749,11 @@ static inline void audit_free_names(struct audit_context *context) | |||
743 | context->serial, context->major, context->in_syscall, | 749 | context->serial, context->major, context->in_syscall, |
744 | context->name_count, context->put_count, | 750 | context->name_count, context->put_count, |
745 | context->ino_count); | 751 | context->ino_count); |
746 | for (i = 0; i < context->name_count; i++) | 752 | for (i = 0; i < context->name_count; i++) { |
747 | printk(KERN_ERR "names[%d] = %p = %s\n", i, | 753 | printk(KERN_ERR "names[%d] = %p = %s\n", i, |
748 | context->names[i].name, | 754 | context->names[i].name, |
749 | context->names[i].name ?: "(null)"); | 755 | context->names[i].name ?: "(null)"); |
756 | } | ||
750 | dump_stack(); | 757 | dump_stack(); |
751 | return; | 758 | return; |
752 | } | 759 | } |
@@ -756,9 +763,13 @@ static inline void audit_free_names(struct audit_context *context) | |||
756 | context->ino_count = 0; | 763 | context->ino_count = 0; |
757 | #endif | 764 | #endif |
758 | 765 | ||
759 | for (i = 0; i < context->name_count; i++) | 766 | for (i = 0; i < context->name_count; i++) { |
767 | char *p = context->names[i].ctx; | ||
768 | context->names[i].ctx = NULL; | ||
769 | kfree(p); | ||
760 | if (context->names[i].name) | 770 | if (context->names[i].name) |
761 | __putname(context->names[i].name); | 771 | __putname(context->names[i].name); |
772 | } | ||
762 | context->name_count = 0; | 773 | context->name_count = 0; |
763 | if (context->pwd) | 774 | if (context->pwd) |
764 | dput(context->pwd); | 775 | dput(context->pwd); |
@@ -778,6 +789,12 @@ static inline void audit_free_aux(struct audit_context *context) | |||
778 | dput(axi->dentry); | 789 | dput(axi->dentry); |
779 | mntput(axi->mnt); | 790 | mntput(axi->mnt); |
780 | } | 791 | } |
792 | if ( aux->type == AUDIT_IPC ) { | ||
793 | struct audit_aux_data_ipcctl *axi = (void *)aux; | ||
794 | if (axi->ctx) | ||
795 | kfree(axi->ctx); | ||
796 | } | ||
797 | |||
781 | context->aux = aux->next; | 798 | context->aux = aux->next; |
782 | kfree(aux); | 799 | kfree(aux); |
783 | } | 800 | } |
@@ -862,7 +879,38 @@ static inline void audit_free_context(struct audit_context *context) | |||
862 | printk(KERN_ERR "audit: freed %d contexts\n", count); | 879 | printk(KERN_ERR "audit: freed %d contexts\n", count); |
863 | } | 880 | } |
864 | 881 | ||
865 | static void audit_log_task_info(struct audit_buffer *ab) | 882 | static void audit_log_task_context(struct audit_buffer *ab, gfp_t gfp_mask) |
883 | { | ||
884 | char *ctx = NULL; | ||
885 | ssize_t len = 0; | ||
886 | |||
887 | len = security_getprocattr(current, "current", NULL, 0); | ||
888 | if (len < 0) { | ||
889 | if (len != -EINVAL) | ||
890 | goto error_path; | ||
891 | return; | ||
892 | } | ||
893 | |||
894 | ctx = kmalloc(len, gfp_mask); | ||
895 | if (!ctx) { | ||
896 | goto error_path; | ||
897 | return; | ||
898 | } | ||
899 | |||
900 | len = security_getprocattr(current, "current", ctx, len); | ||
901 | if (len < 0 ) | ||
902 | goto error_path; | ||
903 | |||
904 | audit_log_format(ab, " subj=%s", ctx); | ||
905 | |||
906 | error_path: | ||
907 | if (ctx) | ||
908 | kfree(ctx); | ||
909 | audit_panic("security_getprocattr error in audit_log_task_context"); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | static void audit_log_task_info(struct audit_buffer *ab, gfp_t gfp_mask) | ||
866 | { | 914 | { |
867 | char name[sizeof(current->comm)]; | 915 | char name[sizeof(current->comm)]; |
868 | struct mm_struct *mm = current->mm; | 916 | struct mm_struct *mm = current->mm; |
@@ -875,6 +923,10 @@ static void audit_log_task_info(struct audit_buffer *ab) | |||
875 | if (!mm) | 923 | if (!mm) |
876 | return; | 924 | return; |
877 | 925 | ||
926 | /* | ||
927 | * this is brittle; all callers that pass GFP_ATOMIC will have | ||
928 | * NULL current->mm and we won't get here. | ||
929 | */ | ||
878 | down_read(&mm->mmap_sem); | 930 | down_read(&mm->mmap_sem); |
879 | vma = mm->mmap; | 931 | vma = mm->mmap; |
880 | while (vma) { | 932 | while (vma) { |
@@ -888,6 +940,7 @@ static void audit_log_task_info(struct audit_buffer *ab) | |||
888 | vma = vma->vm_next; | 940 | vma = vma->vm_next; |
889 | } | 941 | } |
890 | up_read(&mm->mmap_sem); | 942 | up_read(&mm->mmap_sem); |
943 | audit_log_task_context(ab, gfp_mask); | ||
891 | } | 944 | } |
892 | 945 | ||
893 | static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) | 946 | static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) |
@@ -923,7 +976,7 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) | |||
923 | context->gid, | 976 | context->gid, |
924 | context->euid, context->suid, context->fsuid, | 977 | context->euid, context->suid, context->fsuid, |
925 | context->egid, context->sgid, context->fsgid); | 978 | context->egid, context->sgid, context->fsgid); |
926 | audit_log_task_info(ab); | 979 | audit_log_task_info(ab, gfp_mask); |
927 | audit_log_end(ab); | 980 | audit_log_end(ab); |
928 | 981 | ||
929 | for (aux = context->aux; aux; aux = aux->next) { | 982 | for (aux = context->aux; aux; aux = aux->next) { |
@@ -936,8 +989,8 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) | |||
936 | case AUDIT_IPC: { | 989 | case AUDIT_IPC: { |
937 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 990 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
938 | audit_log_format(ab, | 991 | audit_log_format(ab, |
939 | " qbytes=%lx iuid=%u igid=%u mode=%x", | 992 | " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s", |
940 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 993 | axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx); |
941 | break; } | 994 | break; } |
942 | 995 | ||
943 | case AUDIT_SOCKETCALL: { | 996 | case AUDIT_SOCKETCALL: { |
@@ -1001,6 +1054,11 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) | |||
1001 | context->names[i].gid, | 1054 | context->names[i].gid, |
1002 | MAJOR(context->names[i].rdev), | 1055 | MAJOR(context->names[i].rdev), |
1003 | MINOR(context->names[i].rdev)); | 1056 | MINOR(context->names[i].rdev)); |
1057 | if (context->names[i].ctx) { | ||
1058 | audit_log_format(ab, " obj=%s", | ||
1059 | context->names[i].ctx); | ||
1060 | } | ||
1061 | |||
1004 | audit_log_end(ab); | 1062 | audit_log_end(ab); |
1005 | } | 1063 | } |
1006 | } | 1064 | } |
@@ -1243,6 +1301,39 @@ void audit_putname(const char *name) | |||
1243 | #endif | 1301 | #endif |
1244 | } | 1302 | } |
1245 | 1303 | ||
1304 | void audit_inode_context(int idx, const struct inode *inode) | ||
1305 | { | ||
1306 | struct audit_context *context = current->audit_context; | ||
1307 | char *ctx = NULL; | ||
1308 | int len = 0; | ||
1309 | |||
1310 | if (!security_inode_xattr_getsuffix()) | ||
1311 | return; | ||
1312 | |||
1313 | len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), NULL, 0, 0); | ||
1314 | if (len < 0) | ||
1315 | goto error_path; | ||
1316 | |||
1317 | ctx = kmalloc(len, GFP_KERNEL); | ||
1318 | if (!ctx) | ||
1319 | goto error_path; | ||
1320 | |||
1321 | len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), ctx, len, 0); | ||
1322 | if (len < 0) | ||
1323 | goto error_path; | ||
1324 | |||
1325 | kfree(context->names[idx].ctx); | ||
1326 | context->names[idx].ctx = ctx; | ||
1327 | return; | ||
1328 | |||
1329 | error_path: | ||
1330 | if (ctx) | ||
1331 | kfree(ctx); | ||
1332 | audit_panic("error in audit_inode_context"); | ||
1333 | return; | ||
1334 | } | ||
1335 | |||
1336 | |||
1246 | /** | 1337 | /** |
1247 | * audit_inode - store the inode and device from a lookup | 1338 | * audit_inode - store the inode and device from a lookup |
1248 | * @name: name being audited | 1339 | * @name: name being audited |
@@ -1282,6 +1373,7 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | |||
1282 | context->names[idx].uid = inode->i_uid; | 1373 | context->names[idx].uid = inode->i_uid; |
1283 | context->names[idx].gid = inode->i_gid; | 1374 | context->names[idx].gid = inode->i_gid; |
1284 | context->names[idx].rdev = inode->i_rdev; | 1375 | context->names[idx].rdev = inode->i_rdev; |
1376 | audit_inode_context(idx, inode); | ||
1285 | if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && | 1377 | if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && |
1286 | (strcmp(name, ".") != 0)) { | 1378 | (strcmp(name, ".") != 0)) { |
1287 | context->names[idx].ino = (unsigned long)-1; | 1379 | context->names[idx].ino = (unsigned long)-1; |
@@ -1363,6 +1455,7 @@ update_context: | |||
1363 | context->names[idx].uid = inode->i_uid; | 1455 | context->names[idx].uid = inode->i_uid; |
1364 | context->names[idx].gid = inode->i_gid; | 1456 | context->names[idx].gid = inode->i_gid; |
1365 | context->names[idx].rdev = inode->i_rdev; | 1457 | context->names[idx].rdev = inode->i_rdev; |
1458 | audit_inode_context(idx, inode); | ||
1366 | } | 1459 | } |
1367 | } | 1460 | } |
1368 | 1461 | ||
@@ -1423,6 +1516,38 @@ uid_t audit_get_loginuid(struct audit_context *ctx) | |||
1423 | return ctx ? ctx->loginuid : -1; | 1516 | return ctx ? ctx->loginuid : -1; |
1424 | } | 1517 | } |
1425 | 1518 | ||
1519 | static char *audit_ipc_context(struct kern_ipc_perm *ipcp) | ||
1520 | { | ||
1521 | struct audit_context *context = current->audit_context; | ||
1522 | char *ctx = NULL; | ||
1523 | int len = 0; | ||
1524 | |||
1525 | if (likely(!context)) | ||
1526 | return NULL; | ||
1527 | |||
1528 | len = security_ipc_getsecurity(ipcp, NULL, 0); | ||
1529 | if (len == -EOPNOTSUPP) | ||
1530 | goto ret; | ||
1531 | if (len < 0) | ||
1532 | goto error_path; | ||
1533 | |||
1534 | ctx = kmalloc(len, GFP_ATOMIC); | ||
1535 | if (!ctx) | ||
1536 | goto error_path; | ||
1537 | |||
1538 | len = security_ipc_getsecurity(ipcp, ctx, len); | ||
1539 | if (len < 0) | ||
1540 | goto error_path; | ||
1541 | |||
1542 | return ctx; | ||
1543 | |||
1544 | error_path: | ||
1545 | kfree(ctx); | ||
1546 | audit_panic("error in audit_ipc_context"); | ||
1547 | ret: | ||
1548 | return NULL; | ||
1549 | } | ||
1550 | |||
1426 | /** | 1551 | /** |
1427 | * audit_ipc_perms - record audit data for ipc | 1552 | * audit_ipc_perms - record audit data for ipc |
1428 | * @qbytes: msgq bytes | 1553 | * @qbytes: msgq bytes |
@@ -1432,7 +1557,7 @@ uid_t audit_get_loginuid(struct audit_context *ctx) | |||
1432 | * | 1557 | * |
1433 | * Returns 0 for success or NULL context or < 0 on error. | 1558 | * Returns 0 for success or NULL context or < 0 on error. |
1434 | */ | 1559 | */ |
1435 | int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) | 1560 | int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp) |
1436 | { | 1561 | { |
1437 | struct audit_aux_data_ipcctl *ax; | 1562 | struct audit_aux_data_ipcctl *ax; |
1438 | struct audit_context *context = current->audit_context; | 1563 | struct audit_context *context = current->audit_context; |
@@ -1440,7 +1565,7 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) | |||
1440 | if (likely(!context)) | 1565 | if (likely(!context)) |
1441 | return 0; | 1566 | return 0; |
1442 | 1567 | ||
1443 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | 1568 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); |
1444 | if (!ax) | 1569 | if (!ax) |
1445 | return -ENOMEM; | 1570 | return -ENOMEM; |
1446 | 1571 | ||
@@ -1448,6 +1573,7 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) | |||
1448 | ax->uid = uid; | 1573 | ax->uid = uid; |
1449 | ax->gid = gid; | 1574 | ax->gid = gid; |
1450 | ax->mode = mode; | 1575 | ax->mode = mode; |
1576 | ax->ctx = audit_ipc_context(ipcp); | ||
1451 | 1577 | ||
1452 | ax->d.type = AUDIT_IPC; | 1578 | ax->d.type = AUDIT_IPC; |
1453 | ax->d.next = context->aux; | 1579 | ax->d.next = context->aux; |
diff --git a/security/dummy.c b/security/dummy.c index f1a5bd98bf1..6febe7d39fa 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -558,6 +558,11 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag) | |||
558 | return 0; | 558 | return 0; |
559 | } | 559 | } |
560 | 560 | ||
561 | static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size) | ||
562 | { | ||
563 | return -EOPNOTSUPP; | ||
564 | } | ||
565 | |||
561 | static int dummy_msg_msg_alloc_security (struct msg_msg *msg) | 566 | static int dummy_msg_msg_alloc_security (struct msg_msg *msg) |
562 | { | 567 | { |
563 | return 0; | 568 | return 0; |
@@ -959,6 +964,7 @@ void security_fixup_ops (struct security_operations *ops) | |||
959 | set_to_dummy_if_null(ops, task_reparent_to_init); | 964 | set_to_dummy_if_null(ops, task_reparent_to_init); |
960 | set_to_dummy_if_null(ops, task_to_inode); | 965 | set_to_dummy_if_null(ops, task_to_inode); |
961 | set_to_dummy_if_null(ops, ipc_permission); | 966 | set_to_dummy_if_null(ops, ipc_permission); |
967 | set_to_dummy_if_null(ops, ipc_getsecurity); | ||
962 | set_to_dummy_if_null(ops, msg_msg_alloc_security); | 968 | set_to_dummy_if_null(ops, msg_msg_alloc_security); |
963 | set_to_dummy_if_null(ops, msg_msg_free_security); | 969 | set_to_dummy_if_null(ops, msg_msg_free_security); |
964 | set_to_dummy_if_null(ops, msg_queue_alloc_security); | 970 | set_to_dummy_if_null(ops, msg_queue_alloc_security); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b65c201e9ff..9c08a19cc81 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -117,6 +117,32 @@ static struct security_operations *secondary_ops = NULL; | |||
117 | static LIST_HEAD(superblock_security_head); | 117 | static LIST_HEAD(superblock_security_head); |
118 | static DEFINE_SPINLOCK(sb_security_lock); | 118 | static DEFINE_SPINLOCK(sb_security_lock); |
119 | 119 | ||
120 | /* Return security context for a given sid or just the context | ||
121 | length if the buffer is null or length is 0 */ | ||
122 | static int selinux_getsecurity(u32 sid, void *buffer, size_t size) | ||
123 | { | ||
124 | char *context; | ||
125 | unsigned len; | ||
126 | int rc; | ||
127 | |||
128 | rc = security_sid_to_context(sid, &context, &len); | ||
129 | if (rc) | ||
130 | return rc; | ||
131 | |||
132 | if (!buffer || !size) | ||
133 | goto getsecurity_exit; | ||
134 | |||
135 | if (size < len) { | ||
136 | len = -ERANGE; | ||
137 | goto getsecurity_exit; | ||
138 | } | ||
139 | memcpy(buffer, context, len); | ||
140 | |||
141 | getsecurity_exit: | ||
142 | kfree(context); | ||
143 | return len; | ||
144 | } | ||
145 | |||
120 | /* Allocate and free functions for each kind of security blob. */ | 146 | /* Allocate and free functions for each kind of security blob. */ |
121 | 147 | ||
122 | static int task_alloc_security(struct task_struct *task) | 148 | static int task_alloc_security(struct task_struct *task) |
@@ -2209,6 +2235,11 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name) | |||
2209 | return -EACCES; | 2235 | return -EACCES; |
2210 | } | 2236 | } |
2211 | 2237 | ||
2238 | static const char *selinux_inode_xattr_getsuffix(void) | ||
2239 | { | ||
2240 | return XATTR_SELINUX_SUFFIX; | ||
2241 | } | ||
2242 | |||
2212 | /* | 2243 | /* |
2213 | * Copy the in-core inode security context value to the user. If the | 2244 | * Copy the in-core inode security context value to the user. If the |
2214 | * getxattr() prior to this succeeded, check to see if we need to | 2245 | * getxattr() prior to this succeeded, check to see if we need to |
@@ -2219,44 +2250,11 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name) | |||
2219 | static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) | 2250 | static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) |
2220 | { | 2251 | { |
2221 | struct inode_security_struct *isec = inode->i_security; | 2252 | struct inode_security_struct *isec = inode->i_security; |
2222 | char *context; | ||
2223 | unsigned len; | ||
2224 | int rc; | ||
2225 | |||
2226 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) { | ||
2227 | rc = -EOPNOTSUPP; | ||
2228 | goto out; | ||
2229 | } | ||
2230 | |||
2231 | rc = security_sid_to_context(isec->sid, &context, &len); | ||
2232 | if (rc) | ||
2233 | goto out; | ||
2234 | |||
2235 | /* Probe for required buffer size */ | ||
2236 | if (!buffer || !size) { | ||
2237 | rc = len; | ||
2238 | goto out_free; | ||
2239 | } | ||
2240 | 2253 | ||
2241 | if (size < len) { | 2254 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) |
2242 | rc = -ERANGE; | 2255 | return -EOPNOTSUPP; |
2243 | goto out_free; | ||
2244 | } | ||
2245 | 2256 | ||
2246 | if (err > 0) { | 2257 | return selinux_getsecurity(isec->sid, buffer, size); |
2247 | if ((len == err) && !(memcmp(context, buffer, len))) { | ||
2248 | /* Don't need to canonicalize value */ | ||
2249 | rc = err; | ||
2250 | goto out_free; | ||
2251 | } | ||
2252 | memset(buffer, 0, size); | ||
2253 | } | ||
2254 | memcpy(buffer, context, len); | ||
2255 | rc = len; | ||
2256 | out_free: | ||
2257 | kfree(context); | ||
2258 | out: | ||
2259 | return rc; | ||
2260 | } | 2258 | } |
2261 | 2259 | ||
2262 | static int selinux_inode_setsecurity(struct inode *inode, const char *name, | 2260 | static int selinux_inode_setsecurity(struct inode *inode, const char *name, |
@@ -4022,6 +4020,13 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) | |||
4022 | return ipc_has_perm(ipcp, av); | 4020 | return ipc_has_perm(ipcp, av); |
4023 | } | 4021 | } |
4024 | 4022 | ||
4023 | static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size) | ||
4024 | { | ||
4025 | struct ipc_security_struct *isec = ipcp->security; | ||
4026 | |||
4027 | return selinux_getsecurity(isec->sid, buffer, size); | ||
4028 | } | ||
4029 | |||
4025 | /* module stacking operations */ | 4030 | /* module stacking operations */ |
4026 | static int selinux_register_security (const char *name, struct security_operations *ops) | 4031 | static int selinux_register_security (const char *name, struct security_operations *ops) |
4027 | { | 4032 | { |
@@ -4063,8 +4068,7 @@ static int selinux_getprocattr(struct task_struct *p, | |||
4063 | char *name, void *value, size_t size) | 4068 | char *name, void *value, size_t size) |
4064 | { | 4069 | { |
4065 | struct task_security_struct *tsec; | 4070 | struct task_security_struct *tsec; |
4066 | u32 sid, len; | 4071 | u32 sid; |
4067 | char *context; | ||
4068 | int error; | 4072 | int error; |
4069 | 4073 | ||
4070 | if (current != p) { | 4074 | if (current != p) { |
@@ -4073,9 +4077,6 @@ static int selinux_getprocattr(struct task_struct *p, | |||
4073 | return error; | 4077 | return error; |
4074 | } | 4078 | } |
4075 | 4079 | ||
4076 | if (!size) | ||
4077 | return -ERANGE; | ||
4078 | |||
4079 | tsec = p->security; | 4080 | tsec = p->security; |
4080 | 4081 | ||
4081 | if (!strcmp(name, "current")) | 4082 | if (!strcmp(name, "current")) |
@@ -4092,16 +4093,7 @@ static int selinux_getprocattr(struct task_struct *p, | |||
4092 | if (!sid) | 4093 | if (!sid) |
4093 | return 0; | 4094 | return 0; |
4094 | 4095 | ||
4095 | error = security_sid_to_context(sid, &context, &len); | 4096 | return selinux_getsecurity(sid, value, size); |
4096 | if (error) | ||
4097 | return error; | ||
4098 | if (len > size) { | ||
4099 | kfree(context); | ||
4100 | return -ERANGE; | ||
4101 | } | ||
4102 | memcpy(value, context, len); | ||
4103 | kfree(context); | ||
4104 | return len; | ||
4105 | } | 4097 | } |
4106 | 4098 | ||
4107 | static int selinux_setprocattr(struct task_struct *p, | 4099 | static int selinux_setprocattr(struct task_struct *p, |
@@ -4259,6 +4251,7 @@ static struct security_operations selinux_ops = { | |||
4259 | .inode_getxattr = selinux_inode_getxattr, | 4251 | .inode_getxattr = selinux_inode_getxattr, |
4260 | .inode_listxattr = selinux_inode_listxattr, | 4252 | .inode_listxattr = selinux_inode_listxattr, |
4261 | .inode_removexattr = selinux_inode_removexattr, | 4253 | .inode_removexattr = selinux_inode_removexattr, |
4254 | .inode_xattr_getsuffix = selinux_inode_xattr_getsuffix, | ||
4262 | .inode_getsecurity = selinux_inode_getsecurity, | 4255 | .inode_getsecurity = selinux_inode_getsecurity, |
4263 | .inode_setsecurity = selinux_inode_setsecurity, | 4256 | .inode_setsecurity = selinux_inode_setsecurity, |
4264 | .inode_listsecurity = selinux_inode_listsecurity, | 4257 | .inode_listsecurity = selinux_inode_listsecurity, |
@@ -4296,6 +4289,7 @@ static struct security_operations selinux_ops = { | |||
4296 | .task_to_inode = selinux_task_to_inode, | 4289 | .task_to_inode = selinux_task_to_inode, |
4297 | 4290 | ||
4298 | .ipc_permission = selinux_ipc_permission, | 4291 | .ipc_permission = selinux_ipc_permission, |
4292 | .ipc_getsecurity = selinux_ipc_getsecurity, | ||
4299 | 4293 | ||
4300 | .msg_msg_alloc_security = selinux_msg_msg_alloc_security, | 4294 | .msg_msg_alloc_security = selinux_msg_msg_alloc_security, |
4301 | .msg_msg_free_security = selinux_msg_msg_free_security, | 4295 | .msg_msg_free_security = selinux_msg_msg_free_security, |