diff options
-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 8fa1a8fbc04d..1912d8e8ae90 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 7cbef482e13a..ec0bbbc3ffc2 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 1c3eb1b12bfc..45c123ef77a7 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 31917ac730af..4e2256ec7cf3 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 f1a5bd98bf10..6febe7d39fa0 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 b65c201e9ff5..9c08a19cc81b 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, |