diff options
Diffstat (limited to 'security')
44 files changed, 1534 insertions, 502 deletions
diff --git a/security/Kconfig b/security/Kconfig index d23c839038f0..fb363cd81cf6 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
| @@ -113,6 +113,52 @@ config SECURITY_ROOTPLUG | |||
| 113 | 113 | ||
| 114 | If you are unsure how to answer this question, answer N. | 114 | If you are unsure how to answer this question, answer N. |
| 115 | 115 | ||
| 116 | config INTEL_TXT | ||
| 117 | bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)" | ||
| 118 | depends on HAVE_INTEL_TXT | ||
| 119 | help | ||
| 120 | This option enables support for booting the kernel with the | ||
| 121 | Trusted Boot (tboot) module. This will utilize | ||
| 122 | Intel(R) Trusted Execution Technology to perform a measured launch | ||
| 123 | of the kernel. If the system does not support Intel(R) TXT, this | ||
| 124 | will have no effect. | ||
| 125 | |||
| 126 | Intel TXT will provide higher assurance of system configuration and | ||
| 127 | initial state as well as data reset protection. This is used to | ||
| 128 | create a robust initial kernel measurement and verification, which | ||
| 129 | helps to ensure that kernel security mechanisms are functioning | ||
| 130 | correctly. This level of protection requires a root of trust outside | ||
| 131 | of the kernel itself. | ||
| 132 | |||
| 133 | Intel TXT also helps solve real end user concerns about having | ||
| 134 | confidence that their hardware is running the VMM or kernel that | ||
| 135 | it was configured with, especially since they may be responsible for | ||
| 136 | providing such assurances to VMs and services running on it. | ||
| 137 | |||
| 138 | See <http://www.intel.com/technology/security/> for more information | ||
| 139 | about Intel(R) TXT. | ||
| 140 | See <http://tboot.sourceforge.net> for more information about tboot. | ||
| 141 | See Documentation/intel_txt.txt for a description of how to enable | ||
| 142 | Intel TXT support in a kernel boot. | ||
| 143 | |||
| 144 | If you are unsure as to whether this is required, answer N. | ||
| 145 | |||
| 146 | config LSM_MMAP_MIN_ADDR | ||
| 147 | int "Low address space for LSM to protect from user allocation" | ||
| 148 | depends on SECURITY && SECURITY_SELINUX | ||
| 149 | default 65536 | ||
| 150 | help | ||
| 151 | This is the portion of low virtual memory which should be protected | ||
| 152 | from userspace allocation. Keeping a user from writing to low pages | ||
| 153 | can help reduce the impact of kernel NULL pointer bugs. | ||
| 154 | |||
| 155 | For most ia64, ppc64 and x86 users with lots of address space | ||
| 156 | a value of 65536 is reasonable and should cause no problems. | ||
| 157 | On arm and other archs it should not be higher than 32768. | ||
| 158 | Programs which use vm86 functionality or have some need to map | ||
| 159 | this low address space will need the permission specific to the | ||
| 160 | systems running LSM. | ||
| 161 | |||
| 116 | source security/selinux/Kconfig | 162 | source security/selinux/Kconfig |
| 117 | source security/smack/Kconfig | 163 | source security/smack/Kconfig |
| 118 | source security/tomoyo/Kconfig | 164 | source security/tomoyo/Kconfig |
diff --git a/security/Makefile b/security/Makefile index c67557cdaa85..95ecc06392d7 100644 --- a/security/Makefile +++ b/security/Makefile | |||
| @@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack | |||
| 8 | subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo | 8 | subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo |
| 9 | 9 | ||
| 10 | # always enable default capabilities | 10 | # always enable default capabilities |
| 11 | obj-y += commoncap.o | 11 | obj-y += commoncap.o min_addr.o |
| 12 | 12 | ||
| 13 | # Object file lists | 13 | # Object file lists |
| 14 | obj-$(CONFIG_SECURITY) += security.o capability.o | 14 | obj-$(CONFIG_SECURITY) += security.o capability.o |
| @@ -16,9 +16,7 @@ obj-$(CONFIG_SECURITYFS) += inode.o | |||
| 16 | # Must precede capability.o in order to stack properly. | 16 | # Must precede capability.o in order to stack properly. |
| 17 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | 17 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o |
| 18 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o | 18 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o |
| 19 | ifeq ($(CONFIG_AUDIT),y) | 19 | obj-$(CONFIG_AUDIT) += lsm_audit.o |
| 20 | obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o | ||
| 21 | endif | ||
| 22 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o | 20 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o |
| 23 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o | 21 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o |
| 24 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 22 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
diff --git a/security/capability.c b/security/capability.c index 21b6cead6a8e..fce07a7bc825 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -330,15 +330,6 @@ static int cap_file_ioctl(struct file *file, unsigned int command, | |||
| 330 | return 0; | 330 | return 0; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | static int cap_file_mmap(struct file *file, unsigned long reqprot, | ||
| 334 | unsigned long prot, unsigned long flags, | ||
| 335 | unsigned long addr, unsigned long addr_only) | ||
| 336 | { | ||
| 337 | if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) | ||
| 338 | return -EACCES; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, | 333 | static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, |
| 343 | unsigned long prot) | 334 | unsigned long prot) |
| 344 | { | 335 | { |
| @@ -382,6 +373,11 @@ static int cap_task_create(unsigned long clone_flags) | |||
| 382 | return 0; | 373 | return 0; |
| 383 | } | 374 | } |
| 384 | 375 | ||
| 376 | static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 377 | { | ||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 385 | static void cap_cred_free(struct cred *cred) | 381 | static void cap_cred_free(struct cred *cred) |
| 386 | { | 382 | { |
| 387 | } | 383 | } |
| @@ -395,6 +391,10 @@ static void cap_cred_commit(struct cred *new, const struct cred *old) | |||
| 395 | { | 391 | { |
| 396 | } | 392 | } |
| 397 | 393 | ||
| 394 | static void cap_cred_transfer(struct cred *new, const struct cred *old) | ||
| 395 | { | ||
| 396 | } | ||
| 397 | |||
| 398 | static int cap_kernel_act_as(struct cred *new, u32 secid) | 398 | static int cap_kernel_act_as(struct cred *new, u32 secid) |
| 399 | { | 399 | { |
| 400 | return 0; | 400 | return 0; |
| @@ -405,6 +405,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 405 | return 0; | 405 | return 0; |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | static int cap_kernel_module_request(void) | ||
| 409 | { | ||
| 410 | return 0; | ||
| 411 | } | ||
| 412 | |||
| 408 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 413 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 409 | { | 414 | { |
| 410 | return 0; | 415 | return 0; |
| @@ -710,10 +715,26 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
| 710 | { | 715 | { |
| 711 | } | 716 | } |
| 712 | 717 | ||
| 718 | |||
| 719 | |||
| 713 | static void cap_req_classify_flow(const struct request_sock *req, | 720 | static void cap_req_classify_flow(const struct request_sock *req, |
| 714 | struct flowi *fl) | 721 | struct flowi *fl) |
| 715 | { | 722 | { |
| 716 | } | 723 | } |
| 724 | |||
| 725 | static int cap_tun_dev_create(void) | ||
| 726 | { | ||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | static void cap_tun_dev_post_create(struct sock *sk) | ||
| 731 | { | ||
| 732 | } | ||
| 733 | |||
| 734 | static int cap_tun_dev_attach(struct sock *sk) | ||
| 735 | { | ||
| 736 | return 0; | ||
| 737 | } | ||
| 717 | #endif /* CONFIG_SECURITY_NETWORK */ | 738 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 718 | 739 | ||
| 719 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 740 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| @@ -801,6 +822,20 @@ static void cap_release_secctx(char *secdata, u32 seclen) | |||
| 801 | { | 822 | { |
| 802 | } | 823 | } |
| 803 | 824 | ||
| 825 | static int cap_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 826 | { | ||
| 827 | return 0; | ||
| 828 | } | ||
| 829 | |||
| 830 | static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 831 | { | ||
| 832 | return 0; | ||
| 833 | } | ||
| 834 | |||
| 835 | static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 836 | { | ||
| 837 | return 0; | ||
| 838 | } | ||
| 804 | #ifdef CONFIG_KEYS | 839 | #ifdef CONFIG_KEYS |
| 805 | static int cap_key_alloc(struct key *key, const struct cred *cred, | 840 | static int cap_key_alloc(struct key *key, const struct cred *cred, |
| 806 | unsigned long flags) | 841 | unsigned long flags) |
| @@ -824,6 +859,13 @@ static int cap_key_getsecurity(struct key *key, char **_buffer) | |||
| 824 | return 0; | 859 | return 0; |
| 825 | } | 860 | } |
| 826 | 861 | ||
| 862 | static int cap_key_session_to_parent(const struct cred *cred, | ||
| 863 | const struct cred *parent_cred, | ||
| 864 | struct key *key) | ||
| 865 | { | ||
| 866 | return 0; | ||
| 867 | } | ||
| 868 | |||
| 827 | #endif /* CONFIG_KEYS */ | 869 | #endif /* CONFIG_KEYS */ |
| 828 | 870 | ||
| 829 | #ifdef CONFIG_AUDIT | 871 | #ifdef CONFIG_AUDIT |
| @@ -863,7 +905,7 @@ struct security_operations default_security_ops = { | |||
| 863 | 905 | ||
| 864 | void security_fixup_ops(struct security_operations *ops) | 906 | void security_fixup_ops(struct security_operations *ops) |
| 865 | { | 907 | { |
| 866 | set_to_cap_if_null(ops, ptrace_may_access); | 908 | set_to_cap_if_null(ops, ptrace_access_check); |
| 867 | set_to_cap_if_null(ops, ptrace_traceme); | 909 | set_to_cap_if_null(ops, ptrace_traceme); |
| 868 | set_to_cap_if_null(ops, capget); | 910 | set_to_cap_if_null(ops, capget); |
| 869 | set_to_cap_if_null(ops, capset); | 911 | set_to_cap_if_null(ops, capset); |
| @@ -949,11 +991,14 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 949 | set_to_cap_if_null(ops, file_receive); | 991 | set_to_cap_if_null(ops, file_receive); |
| 950 | set_to_cap_if_null(ops, dentry_open); | 992 | set_to_cap_if_null(ops, dentry_open); |
| 951 | set_to_cap_if_null(ops, task_create); | 993 | set_to_cap_if_null(ops, task_create); |
| 994 | set_to_cap_if_null(ops, cred_alloc_blank); | ||
| 952 | set_to_cap_if_null(ops, cred_free); | 995 | set_to_cap_if_null(ops, cred_free); |
| 953 | set_to_cap_if_null(ops, cred_prepare); | 996 | set_to_cap_if_null(ops, cred_prepare); |
| 954 | set_to_cap_if_null(ops, cred_commit); | 997 | set_to_cap_if_null(ops, cred_commit); |
| 998 | set_to_cap_if_null(ops, cred_transfer); | ||
| 955 | set_to_cap_if_null(ops, kernel_act_as); | 999 | set_to_cap_if_null(ops, kernel_act_as); |
| 956 | set_to_cap_if_null(ops, kernel_create_files_as); | 1000 | set_to_cap_if_null(ops, kernel_create_files_as); |
| 1001 | set_to_cap_if_null(ops, kernel_module_request); | ||
| 957 | set_to_cap_if_null(ops, task_setuid); | 1002 | set_to_cap_if_null(ops, task_setuid); |
| 958 | set_to_cap_if_null(ops, task_fix_setuid); | 1003 | set_to_cap_if_null(ops, task_fix_setuid); |
| 959 | set_to_cap_if_null(ops, task_setgid); | 1004 | set_to_cap_if_null(ops, task_setgid); |
| @@ -1001,6 +1046,9 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1001 | set_to_cap_if_null(ops, secid_to_secctx); | 1046 | set_to_cap_if_null(ops, secid_to_secctx); |
| 1002 | set_to_cap_if_null(ops, secctx_to_secid); | 1047 | set_to_cap_if_null(ops, secctx_to_secid); |
| 1003 | set_to_cap_if_null(ops, release_secctx); | 1048 | set_to_cap_if_null(ops, release_secctx); |
| 1049 | set_to_cap_if_null(ops, inode_notifysecctx); | ||
| 1050 | set_to_cap_if_null(ops, inode_setsecctx); | ||
| 1051 | set_to_cap_if_null(ops, inode_getsecctx); | ||
| 1004 | #ifdef CONFIG_SECURITY_NETWORK | 1052 | #ifdef CONFIG_SECURITY_NETWORK |
| 1005 | set_to_cap_if_null(ops, unix_stream_connect); | 1053 | set_to_cap_if_null(ops, unix_stream_connect); |
| 1006 | set_to_cap_if_null(ops, unix_may_send); | 1054 | set_to_cap_if_null(ops, unix_may_send); |
| @@ -1029,6 +1077,9 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1029 | set_to_cap_if_null(ops, inet_csk_clone); | 1077 | set_to_cap_if_null(ops, inet_csk_clone); |
| 1030 | set_to_cap_if_null(ops, inet_conn_established); | 1078 | set_to_cap_if_null(ops, inet_conn_established); |
| 1031 | set_to_cap_if_null(ops, req_classify_flow); | 1079 | set_to_cap_if_null(ops, req_classify_flow); |
| 1080 | set_to_cap_if_null(ops, tun_dev_create); | ||
| 1081 | set_to_cap_if_null(ops, tun_dev_post_create); | ||
| 1082 | set_to_cap_if_null(ops, tun_dev_attach); | ||
| 1032 | #endif /* CONFIG_SECURITY_NETWORK */ | 1083 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1033 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1084 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 1034 | set_to_cap_if_null(ops, xfrm_policy_alloc_security); | 1085 | set_to_cap_if_null(ops, xfrm_policy_alloc_security); |
| @@ -1047,6 +1098,7 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1047 | set_to_cap_if_null(ops, key_free); | 1098 | set_to_cap_if_null(ops, key_free); |
| 1048 | set_to_cap_if_null(ops, key_permission); | 1099 | set_to_cap_if_null(ops, key_permission); |
| 1049 | set_to_cap_if_null(ops, key_getsecurity); | 1100 | set_to_cap_if_null(ops, key_getsecurity); |
| 1101 | set_to_cap_if_null(ops, key_session_to_parent); | ||
| 1050 | #endif /* CONFIG_KEYS */ | 1102 | #endif /* CONFIG_KEYS */ |
| 1051 | #ifdef CONFIG_AUDIT | 1103 | #ifdef CONFIG_AUDIT |
| 1052 | set_to_cap_if_null(ops, audit_rule_init); | 1104 | set_to_cap_if_null(ops, audit_rule_init); |
diff --git a/security/commoncap.c b/security/commoncap.c index 48b7e0228fa3..fe30751a6cd9 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -101,7 +101,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * cap_ptrace_may_access - Determine whether the current process may access | 104 | * cap_ptrace_access_check - Determine whether the current process may access |
| 105 | * another | 105 | * another |
| 106 | * @child: The process to be accessed | 106 | * @child: The process to be accessed |
| 107 | * @mode: The mode of attachment. | 107 | * @mode: The mode of attachment. |
| @@ -109,7 +109,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
| 109 | * Determine whether a process may access another, returning 0 if permission | 109 | * Determine whether a process may access another, returning 0 if permission |
| 110 | * granted, -ve if denied. | 110 | * granted, -ve if denied. |
| 111 | */ | 111 | */ |
| 112 | int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) | 112 | int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) |
| 113 | { | 113 | { |
| 114 | int ret = 0; | 114 | int ret = 0; |
| 115 | 115 | ||
| @@ -984,3 +984,33 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 984 | cap_sys_admin = 1; | 984 | cap_sys_admin = 1; |
| 985 | return __vm_enough_memory(mm, pages, cap_sys_admin); | 985 | return __vm_enough_memory(mm, pages, cap_sys_admin); |
| 986 | } | 986 | } |
| 987 | |||
| 988 | /* | ||
| 989 | * cap_file_mmap - check if able to map given addr | ||
| 990 | * @file: unused | ||
| 991 | * @reqprot: unused | ||
| 992 | * @prot: unused | ||
| 993 | * @flags: unused | ||
| 994 | * @addr: address attempting to be mapped | ||
| 995 | * @addr_only: unused | ||
| 996 | * | ||
| 997 | * If the process is attempting to map memory below mmap_min_addr they need | ||
| 998 | * CAP_SYS_RAWIO. The other parameters to this function are unused by the | ||
| 999 | * capability security module. Returns 0 if this mapping should be allowed | ||
| 1000 | * -EPERM if not. | ||
| 1001 | */ | ||
| 1002 | int cap_file_mmap(struct file *file, unsigned long reqprot, | ||
| 1003 | unsigned long prot, unsigned long flags, | ||
| 1004 | unsigned long addr, unsigned long addr_only) | ||
| 1005 | { | ||
| 1006 | int ret = 0; | ||
| 1007 | |||
| 1008 | if (addr < dac_mmap_min_addr) { | ||
| 1009 | ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO, | ||
| 1010 | SECURITY_CAP_AUDIT); | ||
| 1011 | /* set PF_SUPERPRIV if it turns out we allow the low mmap */ | ||
| 1012 | if (ret == 0) | ||
| 1013 | current->flags |= PF_SUPERPRIV; | ||
| 1014 | } | ||
| 1015 | return ret; | ||
| 1016 | } | ||
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index b8186bac8b7e..6cf8fd2b79e8 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
| @@ -61,7 +61,8 @@ static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) | |||
| 61 | struct cgroup_subsys devices_subsys; | 61 | struct cgroup_subsys devices_subsys; |
| 62 | 62 | ||
| 63 | static int devcgroup_can_attach(struct cgroup_subsys *ss, | 63 | static int devcgroup_can_attach(struct cgroup_subsys *ss, |
| 64 | struct cgroup *new_cgroup, struct task_struct *task) | 64 | struct cgroup *new_cgroup, struct task_struct *task, |
| 65 | bool threadgroup) | ||
| 65 | { | 66 | { |
| 66 | if (current != task && !capable(CAP_SYS_ADMIN)) | 67 | if (current != task && !capable(CAP_SYS_ADMIN)) |
| 67 | return -EPERM; | 68 | return -EPERM; |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 63003a63aaee..46642a19bc78 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -45,9 +45,9 @@ int ima_calc_hash(struct file *file, char *digest) | |||
| 45 | { | 45 | { |
| 46 | struct hash_desc desc; | 46 | struct hash_desc desc; |
| 47 | struct scatterlist sg[1]; | 47 | struct scatterlist sg[1]; |
| 48 | loff_t i_size; | 48 | loff_t i_size, offset = 0; |
| 49 | char *rbuf; | 49 | char *rbuf; |
| 50 | int rc, offset = 0; | 50 | int rc; |
| 51 | 51 | ||
| 52 | rc = init_desc(&desc); | 52 | rc = init_desc(&desc); |
| 53 | if (rc != 0) | 53 | if (rc != 0) |
| @@ -67,6 +67,8 @@ int ima_calc_hash(struct file *file, char *digest) | |||
| 67 | rc = rbuf_len; | 67 | rc = rbuf_len; |
| 68 | break; | 68 | break; |
| 69 | } | 69 | } |
| 70 | if (rbuf_len == 0) | ||
| 71 | break; | ||
| 70 | offset += rbuf_len; | 72 | offset += rbuf_len; |
| 71 | sg_init_one(sg, rbuf, rbuf_len); | 73 | sg_init_one(sg, rbuf, rbuf_len); |
| 72 | 74 | ||
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 6bfc7eaebfda..0c72c9c38956 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
| @@ -43,7 +43,7 @@ static ssize_t ima_show_htable_violations(struct file *filp, | |||
| 43 | return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); | 43 | return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static struct file_operations ima_htable_violations_ops = { | 46 | static const struct file_operations ima_htable_violations_ops = { |
| 47 | .read = ima_show_htable_violations | 47 | .read = ima_show_htable_violations |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| @@ -55,7 +55,7 @@ static ssize_t ima_show_measurements_count(struct file *filp, | |||
| 55 | 55 | ||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | static struct file_operations ima_measurements_count_ops = { | 58 | static const struct file_operations ima_measurements_count_ops = { |
| 59 | .read = ima_show_measurements_count | 59 | .read = ima_show_measurements_count |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| @@ -146,7 +146,7 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
| 146 | return 0; | 146 | return 0; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | static struct seq_operations ima_measurments_seqops = { | 149 | static const struct seq_operations ima_measurments_seqops = { |
| 150 | .start = ima_measurements_start, | 150 | .start = ima_measurements_start, |
| 151 | .next = ima_measurements_next, | 151 | .next = ima_measurements_next, |
| 152 | .stop = ima_measurements_stop, | 152 | .stop = ima_measurements_stop, |
| @@ -158,7 +158,7 @@ static int ima_measurements_open(struct inode *inode, struct file *file) | |||
| 158 | return seq_open(file, &ima_measurments_seqops); | 158 | return seq_open(file, &ima_measurments_seqops); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | static struct file_operations ima_measurements_ops = { | 161 | static const struct file_operations ima_measurements_ops = { |
| 162 | .open = ima_measurements_open, | 162 | .open = ima_measurements_open, |
| 163 | .read = seq_read, | 163 | .read = seq_read, |
| 164 | .llseek = seq_lseek, | 164 | .llseek = seq_lseek, |
| @@ -221,7 +221,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) | |||
| 221 | return 0; | 221 | return 0; |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | static struct seq_operations ima_ascii_measurements_seqops = { | 224 | static const struct seq_operations ima_ascii_measurements_seqops = { |
| 225 | .start = ima_measurements_start, | 225 | .start = ima_measurements_start, |
| 226 | .next = ima_measurements_next, | 226 | .next = ima_measurements_next, |
| 227 | .stop = ima_measurements_stop, | 227 | .stop = ima_measurements_stop, |
| @@ -233,7 +233,7 @@ static int ima_ascii_measurements_open(struct inode *inode, struct file *file) | |||
| 233 | return seq_open(file, &ima_ascii_measurements_seqops); | 233 | return seq_open(file, &ima_ascii_measurements_seqops); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | static struct file_operations ima_ascii_measurements_ops = { | 236 | static const struct file_operations ima_ascii_measurements_ops = { |
| 237 | .open = ima_ascii_measurements_open, | 237 | .open = ima_ascii_measurements_open, |
| 238 | .read = seq_read, | 238 | .read = seq_read, |
| 239 | .llseek = seq_lseek, | 239 | .llseek = seq_lseek, |
| @@ -313,7 +313,7 @@ static int ima_release_policy(struct inode *inode, struct file *file) | |||
| 313 | return 0; | 313 | return 0; |
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | static struct file_operations ima_measure_policy_ops = { | 316 | static const struct file_operations ima_measure_policy_ops = { |
| 317 | .open = ima_open_policy, | 317 | .open = ima_open_policy, |
| 318 | .write = ima_write_policy, | 318 | .write = ima_write_policy, |
| 319 | .release = ima_release_policy | 319 | .release = ima_release_policy |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 101c512564ec..b85e61bcf246 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -249,7 +249,11 @@ void ima_counts_put(struct path *path, int mask) | |||
| 249 | struct inode *inode = path->dentry->d_inode; | 249 | struct inode *inode = path->dentry->d_inode; |
| 250 | struct ima_iint_cache *iint; | 250 | struct ima_iint_cache *iint; |
| 251 | 251 | ||
| 252 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 252 | /* The inode may already have been freed, freeing the iint |
| 253 | * with it. Verify the inode is not NULL before dereferencing | ||
| 254 | * it. | ||
| 255 | */ | ||
| 256 | if (!ima_initialized || !inode || !S_ISREG(inode->i_mode)) | ||
| 253 | return; | 257 | return; |
| 254 | iint = ima_iint_find_insert_get(inode); | 258 | iint = ima_iint_find_insert_get(inode); |
| 255 | if (!iint) | 259 | if (!iint) |
| @@ -262,6 +266,8 @@ void ima_counts_put(struct path *path, int mask) | |||
| 262 | else if (mask & (MAY_READ | MAY_EXEC)) | 266 | else if (mask & (MAY_READ | MAY_EXEC)) |
| 263 | iint->readcount--; | 267 | iint->readcount--; |
| 264 | mutex_unlock(&iint->mutex); | 268 | mutex_unlock(&iint->mutex); |
| 269 | |||
| 270 | kref_put(&iint->refcount, iint_free); | ||
| 265 | } | 271 | } |
| 266 | 272 | ||
| 267 | /* | 273 | /* |
| @@ -291,6 +297,8 @@ void ima_counts_get(struct file *file) | |||
| 291 | if (file->f_mode & FMODE_WRITE) | 297 | if (file->f_mode & FMODE_WRITE) |
| 292 | iint->writecount++; | 298 | iint->writecount++; |
| 293 | mutex_unlock(&iint->mutex); | 299 | mutex_unlock(&iint->mutex); |
| 300 | |||
| 301 | kref_put(&iint->refcount, iint_free); | ||
| 294 | } | 302 | } |
| 295 | EXPORT_SYMBOL_GPL(ima_counts_get); | 303 | EXPORT_SYMBOL_GPL(ima_counts_get); |
| 296 | 304 | ||
diff --git a/security/keys/Makefile b/security/keys/Makefile index 747a464943af..74d5447d7df7 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := \ | 5 | obj-y := \ |
| 6 | gc.o \ | ||
| 6 | key.o \ | 7 | key.o \ |
| 7 | keyring.o \ | 8 | keyring.o \ |
| 8 | keyctl.o \ | 9 | keyctl.o \ |
diff --git a/security/keys/compat.c b/security/keys/compat.c index c766c68a63bc..792c0a611a6d 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
| @@ -82,6 +82,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
| 82 | case KEYCTL_GET_SECURITY: | 82 | case KEYCTL_GET_SECURITY: |
| 83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); | 83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); |
| 84 | 84 | ||
| 85 | case KEYCTL_SESSION_TO_PARENT: | ||
| 86 | return keyctl_session_to_parent(); | ||
| 87 | |||
| 85 | default: | 88 | default: |
| 86 | return -EOPNOTSUPP; | 89 | return -EOPNOTSUPP; |
| 87 | } | 90 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c new file mode 100644 index 000000000000..4770be375ffe --- /dev/null +++ b/security/keys/gc.c | |||
| @@ -0,0 +1,218 @@ | |||
| 1 | /* Key garbage collector | ||
| 2 | * | ||
| 3 | * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <keys/keyring-type.h> | ||
| 14 | #include "internal.h" | ||
| 15 | |||
| 16 | /* | ||
| 17 | * Delay between key revocation/expiry in seconds | ||
| 18 | */ | ||
| 19 | unsigned key_gc_delay = 5 * 60; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Reaper | ||
| 23 | */ | ||
| 24 | static void key_gc_timer_func(unsigned long); | ||
| 25 | static void key_garbage_collector(struct work_struct *); | ||
| 26 | static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); | ||
| 27 | static DECLARE_WORK(key_gc_work, key_garbage_collector); | ||
| 28 | static key_serial_t key_gc_cursor; /* the last key the gc considered */ | ||
| 29 | static bool key_gc_again; | ||
| 30 | static unsigned long key_gc_executing; | ||
| 31 | static time_t key_gc_next_run = LONG_MAX; | ||
| 32 | static time_t key_gc_new_timer; | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Schedule a garbage collection run | ||
| 36 | * - precision isn't particularly important | ||
| 37 | */ | ||
| 38 | void key_schedule_gc(time_t gc_at) | ||
| 39 | { | ||
| 40 | unsigned long expires; | ||
| 41 | time_t now = current_kernel_time().tv_sec; | ||
| 42 | |||
| 43 | kenter("%ld", gc_at - now); | ||
| 44 | |||
| 45 | if (gc_at <= now) { | ||
| 46 | schedule_work(&key_gc_work); | ||
| 47 | } else if (gc_at < key_gc_next_run) { | ||
| 48 | expires = jiffies + (gc_at - now) * HZ; | ||
| 49 | mod_timer(&key_gc_timer, expires); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | /* | ||
| 54 | * The garbage collector timer kicked off | ||
| 55 | */ | ||
| 56 | static void key_gc_timer_func(unsigned long data) | ||
| 57 | { | ||
| 58 | kenter(""); | ||
| 59 | key_gc_next_run = LONG_MAX; | ||
| 60 | schedule_work(&key_gc_work); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Garbage collect pointers from a keyring | ||
| 65 | * - return true if we altered the keyring | ||
| 66 | */ | ||
| 67 | static bool key_gc_keyring(struct key *keyring, time_t limit) | ||
| 68 | __releases(key_serial_lock) | ||
| 69 | { | ||
| 70 | struct keyring_list *klist; | ||
| 71 | struct key *key; | ||
| 72 | int loop; | ||
| 73 | |||
| 74 | kenter("%x", key_serial(keyring)); | ||
| 75 | |||
| 76 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | ||
| 77 | goto dont_gc; | ||
| 78 | |||
| 79 | /* scan the keyring looking for dead keys */ | ||
| 80 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
| 81 | if (!klist) | ||
| 82 | goto dont_gc; | ||
| 83 | |||
| 84 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | ||
| 85 | key = klist->keys[loop]; | ||
| 86 | if (test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
| 87 | (key->expiry > 0 && key->expiry <= limit)) | ||
| 88 | goto do_gc; | ||
| 89 | } | ||
| 90 | |||
| 91 | dont_gc: | ||
| 92 | kleave(" = false"); | ||
| 93 | return false; | ||
| 94 | |||
| 95 | do_gc: | ||
| 96 | key_gc_cursor = keyring->serial; | ||
| 97 | key_get(keyring); | ||
| 98 | spin_unlock(&key_serial_lock); | ||
| 99 | keyring_gc(keyring, limit); | ||
| 100 | key_put(keyring); | ||
| 101 | kleave(" = true"); | ||
| 102 | return true; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Garbage collector for keys | ||
| 107 | * - this involves scanning the keyrings for dead, expired and revoked keys | ||
| 108 | * that have overstayed their welcome | ||
| 109 | */ | ||
| 110 | static void key_garbage_collector(struct work_struct *work) | ||
| 111 | { | ||
| 112 | struct rb_node *rb; | ||
| 113 | key_serial_t cursor; | ||
| 114 | struct key *key, *xkey; | ||
| 115 | time_t new_timer = LONG_MAX, limit, now; | ||
| 116 | |||
| 117 | now = current_kernel_time().tv_sec; | ||
| 118 | kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now); | ||
| 119 | |||
| 120 | if (test_and_set_bit(0, &key_gc_executing)) { | ||
| 121 | key_schedule_gc(current_kernel_time().tv_sec + 1); | ||
| 122 | kleave(" [busy; deferring]"); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | limit = now; | ||
| 127 | if (limit > key_gc_delay) | ||
| 128 | limit -= key_gc_delay; | ||
| 129 | else | ||
| 130 | limit = key_gc_delay; | ||
| 131 | |||
| 132 | spin_lock(&key_serial_lock); | ||
| 133 | |||
| 134 | if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) { | ||
| 135 | spin_unlock(&key_serial_lock); | ||
| 136 | clear_bit(0, &key_gc_executing); | ||
| 137 | return; | ||
| 138 | } | ||
| 139 | |||
| 140 | cursor = key_gc_cursor; | ||
| 141 | if (cursor < 0) | ||
| 142 | cursor = 0; | ||
| 143 | if (cursor > 0) | ||
| 144 | new_timer = key_gc_new_timer; | ||
| 145 | else | ||
| 146 | key_gc_again = false; | ||
| 147 | |||
| 148 | /* find the first key above the cursor */ | ||
| 149 | key = NULL; | ||
| 150 | rb = key_serial_tree.rb_node; | ||
| 151 | while (rb) { | ||
| 152 | xkey = rb_entry(rb, struct key, serial_node); | ||
| 153 | if (cursor < xkey->serial) { | ||
| 154 | key = xkey; | ||
| 155 | rb = rb->rb_left; | ||
| 156 | } else if (cursor > xkey->serial) { | ||
| 157 | rb = rb->rb_right; | ||
| 158 | } else { | ||
| 159 | rb = rb_next(rb); | ||
| 160 | if (!rb) | ||
| 161 | goto reached_the_end; | ||
| 162 | key = rb_entry(rb, struct key, serial_node); | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | if (!key) | ||
| 168 | goto reached_the_end; | ||
| 169 | |||
| 170 | /* trawl through the keys looking for keyrings */ | ||
| 171 | for (;;) { | ||
| 172 | if (key->expiry > limit && key->expiry < new_timer) { | ||
| 173 | kdebug("will expire %x in %ld", | ||
| 174 | key_serial(key), key->expiry - limit); | ||
| 175 | new_timer = key->expiry; | ||
| 176 | } | ||
| 177 | |||
| 178 | if (key->type == &key_type_keyring && | ||
| 179 | key_gc_keyring(key, limit)) | ||
| 180 | /* the gc had to release our lock so that the keyring | ||
| 181 | * could be modified, so we have to get it again */ | ||
| 182 | goto gc_released_our_lock; | ||
| 183 | |||
| 184 | rb = rb_next(&key->serial_node); | ||
| 185 | if (!rb) | ||
| 186 | goto reached_the_end; | ||
| 187 | key = rb_entry(rb, struct key, serial_node); | ||
| 188 | } | ||
| 189 | |||
| 190 | gc_released_our_lock: | ||
| 191 | kdebug("gc_released_our_lock"); | ||
| 192 | key_gc_new_timer = new_timer; | ||
| 193 | key_gc_again = true; | ||
| 194 | clear_bit(0, &key_gc_executing); | ||
| 195 | schedule_work(&key_gc_work); | ||
| 196 | kleave(" [continue]"); | ||
| 197 | return; | ||
| 198 | |||
| 199 | /* when we reach the end of the run, we set the timer for the next one */ | ||
| 200 | reached_the_end: | ||
| 201 | kdebug("reached_the_end"); | ||
| 202 | spin_unlock(&key_serial_lock); | ||
| 203 | key_gc_new_timer = new_timer; | ||
| 204 | key_gc_cursor = 0; | ||
| 205 | clear_bit(0, &key_gc_executing); | ||
| 206 | |||
| 207 | if (key_gc_again) { | ||
| 208 | /* there may have been a key that expired whilst we were | ||
| 209 | * scanning, so if we discarded any links we should do another | ||
| 210 | * scan */ | ||
| 211 | new_timer = now + 1; | ||
| 212 | key_schedule_gc(new_timer); | ||
| 213 | } else if (new_timer < LONG_MAX) { | ||
| 214 | new_timer += key_gc_delay; | ||
| 215 | key_schedule_gc(new_timer); | ||
| 216 | } | ||
| 217 | kleave(" [end]"); | ||
| 218 | } | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 9fb679c66b8a..24ba0307b7ad 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -124,11 +124,18 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
| 124 | struct key *dest_keyring, | 124 | struct key *dest_keyring, |
| 125 | unsigned long flags); | 125 | unsigned long flags); |
| 126 | 126 | ||
| 127 | extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 127 | extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, |
| 128 | key_perm_t perm); | 128 | key_perm_t perm); |
| 129 | #define KEY_LOOKUP_CREATE 0x01 | ||
| 130 | #define KEY_LOOKUP_PARTIAL 0x02 | ||
| 131 | #define KEY_LOOKUP_FOR_UNLINK 0x04 | ||
| 129 | 132 | ||
| 130 | extern long join_session_keyring(const char *name); | 133 | extern long join_session_keyring(const char *name); |
| 131 | 134 | ||
| 135 | extern unsigned key_gc_delay; | ||
| 136 | extern void keyring_gc(struct key *keyring, time_t limit); | ||
| 137 | extern void key_schedule_gc(time_t expiry_at); | ||
| 138 | |||
| 132 | /* | 139 | /* |
| 133 | * check to see whether permission is granted to use a key in the desired way | 140 | * check to see whether permission is granted to use a key in the desired way |
| 134 | */ | 141 | */ |
| @@ -194,6 +201,7 @@ extern long keyctl_set_timeout(key_serial_t, unsigned); | |||
| 194 | extern long keyctl_assume_authority(key_serial_t); | 201 | extern long keyctl_assume_authority(key_serial_t); |
| 195 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | 202 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, |
| 196 | size_t buflen); | 203 | size_t buflen); |
| 204 | extern long keyctl_session_to_parent(void); | ||
| 197 | 205 | ||
| 198 | /* | 206 | /* |
| 199 | * debugging key validation | 207 | * debugging key validation |
diff --git a/security/keys/key.c b/security/keys/key.c index 4a1297d1ada4..e50d264c9ad1 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -500,6 +500,7 @@ int key_negate_and_link(struct key *key, | |||
| 500 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | 500 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
| 501 | now = current_kernel_time(); | 501 | now = current_kernel_time(); |
| 502 | key->expiry = now.tv_sec + timeout; | 502 | key->expiry = now.tv_sec + timeout; |
| 503 | key_schedule_gc(key->expiry + key_gc_delay); | ||
| 503 | 504 | ||
| 504 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) | 505 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
| 505 | awaken = 1; | 506 | awaken = 1; |
| @@ -642,10 +643,8 @@ struct key *key_lookup(key_serial_t id) | |||
| 642 | goto error; | 643 | goto error; |
| 643 | 644 | ||
| 644 | found: | 645 | found: |
| 645 | /* pretend it doesn't exist if it's dead */ | 646 | /* pretend it doesn't exist if it is awaiting deletion */ |
| 646 | if (atomic_read(&key->usage) == 0 || | 647 | if (atomic_read(&key->usage) == 0) |
| 647 | test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
| 648 | key->type == &key_type_dead) | ||
| 649 | goto not_found; | 648 | goto not_found; |
| 650 | 649 | ||
| 651 | /* this races with key_put(), but that doesn't matter since key_put() | 650 | /* this races with key_put(), but that doesn't matter since key_put() |
| @@ -890,6 +889,9 @@ EXPORT_SYMBOL(key_update); | |||
| 890 | */ | 889 | */ |
| 891 | void key_revoke(struct key *key) | 890 | void key_revoke(struct key *key) |
| 892 | { | 891 | { |
| 892 | struct timespec now; | ||
| 893 | time_t time; | ||
| 894 | |||
| 893 | key_check(key); | 895 | key_check(key); |
| 894 | 896 | ||
| 895 | /* make sure no one's trying to change or use the key when we mark it | 897 | /* make sure no one's trying to change or use the key when we mark it |
| @@ -902,6 +904,14 @@ void key_revoke(struct key *key) | |||
| 902 | key->type->revoke) | 904 | key->type->revoke) |
| 903 | key->type->revoke(key); | 905 | key->type->revoke(key); |
| 904 | 906 | ||
| 907 | /* set the death time to no more than the expiry time */ | ||
| 908 | now = current_kernel_time(); | ||
| 909 | time = now.tv_sec; | ||
| 910 | if (key->revoked_at == 0 || key->revoked_at > time) { | ||
| 911 | key->revoked_at = time; | ||
| 912 | key_schedule_gc(key->revoked_at + key_gc_delay); | ||
| 913 | } | ||
| 914 | |||
| 905 | up_write(&key->sem); | 915 | up_write(&key->sem); |
| 906 | 916 | ||
| 907 | } /* end key_revoke() */ | 917 | } /* end key_revoke() */ |
| @@ -958,8 +968,10 @@ void unregister_key_type(struct key_type *ktype) | |||
| 958 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | 968 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { |
| 959 | key = rb_entry(_n, struct key, serial_node); | 969 | key = rb_entry(_n, struct key, serial_node); |
| 960 | 970 | ||
| 961 | if (key->type == ktype) | 971 | if (key->type == ktype) { |
| 962 | key->type = &key_type_dead; | 972 | key->type = &key_type_dead; |
| 973 | set_bit(KEY_FLAG_DEAD, &key->flags); | ||
| 974 | } | ||
| 963 | } | 975 | } |
| 964 | 976 | ||
| 965 | spin_unlock(&key_serial_lock); | 977 | spin_unlock(&key_serial_lock); |
| @@ -984,6 +996,8 @@ void unregister_key_type(struct key_type *ktype) | |||
| 984 | spin_unlock(&key_serial_lock); | 996 | spin_unlock(&key_serial_lock); |
| 985 | up_write(&key_types_sem); | 997 | up_write(&key_types_sem); |
| 986 | 998 | ||
| 999 | key_schedule_gc(0); | ||
| 1000 | |||
| 987 | } /* end unregister_key_type() */ | 1001 | } /* end unregister_key_type() */ |
| 988 | 1002 | ||
| 989 | EXPORT_SYMBOL(unregister_key_type); | 1003 | EXPORT_SYMBOL(unregister_key_type); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 7f09fb897d2b..2fb28efc5326 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | /* find the target keyring (which must be writable) */ | 105 | /* find the target keyring (which must be writable) */ |
| 106 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 106 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 107 | if (IS_ERR(keyring_ref)) { | 107 | if (IS_ERR(keyring_ref)) { |
| 108 | ret = PTR_ERR(keyring_ref); | 108 | ret = PTR_ERR(keyring_ref); |
| 109 | goto error3; | 109 | goto error3; |
| @@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 185 | /* get the destination keyring if specified */ | 185 | /* get the destination keyring if specified */ |
| 186 | dest_ref = NULL; | 186 | dest_ref = NULL; |
| 187 | if (destringid) { | 187 | if (destringid) { |
| 188 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 188 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
| 189 | KEY_WRITE); | ||
| 189 | if (IS_ERR(dest_ref)) { | 190 | if (IS_ERR(dest_ref)) { |
| 190 | ret = PTR_ERR(dest_ref); | 191 | ret = PTR_ERR(dest_ref); |
| 191 | goto error3; | 192 | goto error3; |
| @@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 233 | long keyctl_get_keyring_ID(key_serial_t id, int create) | 234 | long keyctl_get_keyring_ID(key_serial_t id, int create) |
| 234 | { | 235 | { |
| 235 | key_ref_t key_ref; | 236 | key_ref_t key_ref; |
| 237 | unsigned long lflags; | ||
| 236 | long ret; | 238 | long ret; |
| 237 | 239 | ||
| 238 | key_ref = lookup_user_key(id, create, 0, KEY_SEARCH); | 240 | lflags = create ? KEY_LOOKUP_CREATE : 0; |
| 241 | key_ref = lookup_user_key(id, lflags, KEY_SEARCH); | ||
| 239 | if (IS_ERR(key_ref)) { | 242 | if (IS_ERR(key_ref)) { |
| 240 | ret = PTR_ERR(key_ref); | 243 | ret = PTR_ERR(key_ref); |
| 241 | goto error; | 244 | goto error; |
| @@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id, | |||
| 309 | } | 312 | } |
| 310 | 313 | ||
| 311 | /* find the target key (which must be writable) */ | 314 | /* find the target key (which must be writable) */ |
| 312 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 315 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
| 313 | if (IS_ERR(key_ref)) { | 316 | if (IS_ERR(key_ref)) { |
| 314 | ret = PTR_ERR(key_ref); | 317 | ret = PTR_ERR(key_ref); |
| 315 | goto error2; | 318 | goto error2; |
| @@ -337,10 +340,16 @@ long keyctl_revoke_key(key_serial_t id) | |||
| 337 | key_ref_t key_ref; | 340 | key_ref_t key_ref; |
| 338 | long ret; | 341 | long ret; |
| 339 | 342 | ||
| 340 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 343 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
| 341 | if (IS_ERR(key_ref)) { | 344 | if (IS_ERR(key_ref)) { |
| 342 | ret = PTR_ERR(key_ref); | 345 | ret = PTR_ERR(key_ref); |
| 343 | goto error; | 346 | if (ret != -EACCES) |
| 347 | goto error; | ||
| 348 | key_ref = lookup_user_key(id, 0, KEY_SETATTR); | ||
| 349 | if (IS_ERR(key_ref)) { | ||
| 350 | ret = PTR_ERR(key_ref); | ||
| 351 | goto error; | ||
| 352 | } | ||
| 344 | } | 353 | } |
| 345 | 354 | ||
| 346 | key_revoke(key_ref_to_ptr(key_ref)); | 355 | key_revoke(key_ref_to_ptr(key_ref)); |
| @@ -363,7 +372,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
| 363 | key_ref_t keyring_ref; | 372 | key_ref_t keyring_ref; |
| 364 | long ret; | 373 | long ret; |
| 365 | 374 | ||
| 366 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 375 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 367 | if (IS_ERR(keyring_ref)) { | 376 | if (IS_ERR(keyring_ref)) { |
| 368 | ret = PTR_ERR(keyring_ref); | 377 | ret = PTR_ERR(keyring_ref); |
| 369 | goto error; | 378 | goto error; |
| @@ -389,13 +398,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
| 389 | key_ref_t keyring_ref, key_ref; | 398 | key_ref_t keyring_ref, key_ref; |
| 390 | long ret; | 399 | long ret; |
| 391 | 400 | ||
| 392 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 401 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 393 | if (IS_ERR(keyring_ref)) { | 402 | if (IS_ERR(keyring_ref)) { |
| 394 | ret = PTR_ERR(keyring_ref); | 403 | ret = PTR_ERR(keyring_ref); |
| 395 | goto error; | 404 | goto error; |
| 396 | } | 405 | } |
| 397 | 406 | ||
| 398 | key_ref = lookup_user_key(id, 1, 0, KEY_LINK); | 407 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); |
| 399 | if (IS_ERR(key_ref)) { | 408 | if (IS_ERR(key_ref)) { |
| 400 | ret = PTR_ERR(key_ref); | 409 | ret = PTR_ERR(key_ref); |
| 401 | goto error2; | 410 | goto error2; |
| @@ -423,13 +432,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
| 423 | key_ref_t keyring_ref, key_ref; | 432 | key_ref_t keyring_ref, key_ref; |
| 424 | long ret; | 433 | long ret; |
| 425 | 434 | ||
| 426 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE); | 435 | keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); |
| 427 | if (IS_ERR(keyring_ref)) { | 436 | if (IS_ERR(keyring_ref)) { |
| 428 | ret = PTR_ERR(keyring_ref); | 437 | ret = PTR_ERR(keyring_ref); |
| 429 | goto error; | 438 | goto error; |
| 430 | } | 439 | } |
| 431 | 440 | ||
| 432 | key_ref = lookup_user_key(id, 0, 0, 0); | 441 | key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); |
| 433 | if (IS_ERR(key_ref)) { | 442 | if (IS_ERR(key_ref)) { |
| 434 | ret = PTR_ERR(key_ref); | 443 | ret = PTR_ERR(key_ref); |
| 435 | goto error2; | 444 | goto error2; |
| @@ -465,7 +474,7 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 465 | char *tmpbuf; | 474 | char *tmpbuf; |
| 466 | long ret; | 475 | long ret; |
| 467 | 476 | ||
| 468 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 477 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
| 469 | if (IS_ERR(key_ref)) { | 478 | if (IS_ERR(key_ref)) { |
| 470 | /* viewing a key under construction is permitted if we have the | 479 | /* viewing a key under construction is permitted if we have the |
| 471 | * authorisation token handy */ | 480 | * authorisation token handy */ |
| @@ -474,7 +483,8 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 474 | if (!IS_ERR(instkey)) { | 483 | if (!IS_ERR(instkey)) { |
| 475 | key_put(instkey); | 484 | key_put(instkey); |
| 476 | key_ref = lookup_user_key(keyid, | 485 | key_ref = lookup_user_key(keyid, |
| 477 | 0, 1, 0); | 486 | KEY_LOOKUP_PARTIAL, |
| 487 | 0); | ||
| 478 | if (!IS_ERR(key_ref)) | 488 | if (!IS_ERR(key_ref)) |
| 479 | goto okay; | 489 | goto okay; |
| 480 | } | 490 | } |
| @@ -558,7 +568,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 558 | } | 568 | } |
| 559 | 569 | ||
| 560 | /* get the keyring at which to begin the search */ | 570 | /* get the keyring at which to begin the search */ |
| 561 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH); | 571 | keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); |
| 562 | if (IS_ERR(keyring_ref)) { | 572 | if (IS_ERR(keyring_ref)) { |
| 563 | ret = PTR_ERR(keyring_ref); | 573 | ret = PTR_ERR(keyring_ref); |
| 564 | goto error2; | 574 | goto error2; |
| @@ -567,7 +577,8 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 567 | /* get the destination keyring if specified */ | 577 | /* get the destination keyring if specified */ |
| 568 | dest_ref = NULL; | 578 | dest_ref = NULL; |
| 569 | if (destringid) { | 579 | if (destringid) { |
| 570 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 580 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
| 581 | KEY_WRITE); | ||
| 571 | if (IS_ERR(dest_ref)) { | 582 | if (IS_ERR(dest_ref)) { |
| 572 | ret = PTR_ERR(dest_ref); | 583 | ret = PTR_ERR(dest_ref); |
| 573 | goto error3; | 584 | goto error3; |
| @@ -637,7 +648,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
| 637 | long ret; | 648 | long ret; |
| 638 | 649 | ||
| 639 | /* find the key first */ | 650 | /* find the key first */ |
| 640 | key_ref = lookup_user_key(keyid, 0, 0, 0); | 651 | key_ref = lookup_user_key(keyid, 0, 0); |
| 641 | if (IS_ERR(key_ref)) { | 652 | if (IS_ERR(key_ref)) { |
| 642 | ret = -ENOKEY; | 653 | ret = -ENOKEY; |
| 643 | goto error; | 654 | goto error; |
| @@ -700,7 +711,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
| 700 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | 711 | if (uid == (uid_t) -1 && gid == (gid_t) -1) |
| 701 | goto error; | 712 | goto error; |
| 702 | 713 | ||
| 703 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 714 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 715 | KEY_SETATTR); | ||
| 704 | if (IS_ERR(key_ref)) { | 716 | if (IS_ERR(key_ref)) { |
| 705 | ret = PTR_ERR(key_ref); | 717 | ret = PTR_ERR(key_ref); |
| 706 | goto error; | 718 | goto error; |
| @@ -805,7 +817,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
| 805 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) | 817 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) |
| 806 | goto error; | 818 | goto error; |
| 807 | 819 | ||
| 808 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 820 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 821 | KEY_SETATTR); | ||
| 809 | if (IS_ERR(key_ref)) { | 822 | if (IS_ERR(key_ref)) { |
| 810 | ret = PTR_ERR(key_ref); | 823 | ret = PTR_ERR(key_ref); |
| 811 | goto error; | 824 | goto error; |
| @@ -847,7 +860,7 @@ static long get_instantiation_keyring(key_serial_t ringid, | |||
| 847 | 860 | ||
| 848 | /* if a specific keyring is nominated by ID, then use that */ | 861 | /* if a specific keyring is nominated by ID, then use that */ |
| 849 | if (ringid > 0) { | 862 | if (ringid > 0) { |
| 850 | dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 863 | dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 851 | if (IS_ERR(dkref)) | 864 | if (IS_ERR(dkref)) |
| 852 | return PTR_ERR(dkref); | 865 | return PTR_ERR(dkref); |
| 853 | *_dest_keyring = key_ref_to_ptr(dkref); | 866 | *_dest_keyring = key_ref_to_ptr(dkref); |
| @@ -1083,7 +1096,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
| 1083 | time_t expiry; | 1096 | time_t expiry; |
| 1084 | long ret; | 1097 | long ret; |
| 1085 | 1098 | ||
| 1086 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 1099 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 1100 | KEY_SETATTR); | ||
| 1087 | if (IS_ERR(key_ref)) { | 1101 | if (IS_ERR(key_ref)) { |
| 1088 | ret = PTR_ERR(key_ref); | 1102 | ret = PTR_ERR(key_ref); |
| 1089 | goto error; | 1103 | goto error; |
| @@ -1101,6 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
| 1101 | } | 1115 | } |
| 1102 | 1116 | ||
| 1103 | key->expiry = expiry; | 1117 | key->expiry = expiry; |
| 1118 | key_schedule_gc(key->expiry + key_gc_delay); | ||
| 1104 | 1119 | ||
| 1105 | up_write(&key->sem); | 1120 | up_write(&key->sem); |
| 1106 | key_put(key); | 1121 | key_put(key); |
| @@ -1170,7 +1185,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1170 | char *context; | 1185 | char *context; |
| 1171 | long ret; | 1186 | long ret; |
| 1172 | 1187 | ||
| 1173 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 1188 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
| 1174 | if (IS_ERR(key_ref)) { | 1189 | if (IS_ERR(key_ref)) { |
| 1175 | if (PTR_ERR(key_ref) != -EACCES) | 1190 | if (PTR_ERR(key_ref) != -EACCES) |
| 1176 | return PTR_ERR(key_ref); | 1191 | return PTR_ERR(key_ref); |
| @@ -1182,7 +1197,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1182 | return PTR_ERR(key_ref); | 1197 | return PTR_ERR(key_ref); |
| 1183 | key_put(instkey); | 1198 | key_put(instkey); |
| 1184 | 1199 | ||
| 1185 | key_ref = lookup_user_key(keyid, 0, 1, 0); | 1200 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); |
| 1186 | if (IS_ERR(key_ref)) | 1201 | if (IS_ERR(key_ref)) |
| 1187 | return PTR_ERR(key_ref); | 1202 | return PTR_ERR(key_ref); |
| 1188 | } | 1203 | } |
| @@ -1213,6 +1228,106 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1213 | return ret; | 1228 | return ret; |
| 1214 | } | 1229 | } |
| 1215 | 1230 | ||
| 1231 | /* | ||
| 1232 | * attempt to install the calling process's session keyring on the process's | ||
| 1233 | * parent process | ||
| 1234 | * - the keyring must exist and must grant us LINK permission | ||
| 1235 | * - implements keyctl(KEYCTL_SESSION_TO_PARENT) | ||
| 1236 | */ | ||
| 1237 | long keyctl_session_to_parent(void) | ||
| 1238 | { | ||
| 1239 | struct task_struct *me, *parent; | ||
| 1240 | const struct cred *mycred, *pcred; | ||
| 1241 | struct cred *cred, *oldcred; | ||
| 1242 | key_ref_t keyring_r; | ||
| 1243 | int ret; | ||
| 1244 | |||
| 1245 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); | ||
| 1246 | if (IS_ERR(keyring_r)) | ||
| 1247 | return PTR_ERR(keyring_r); | ||
| 1248 | |||
| 1249 | /* our parent is going to need a new cred struct, a new tgcred struct | ||
| 1250 | * and new security data, so we allocate them here to prevent ENOMEM in | ||
| 1251 | * our parent */ | ||
| 1252 | ret = -ENOMEM; | ||
| 1253 | cred = cred_alloc_blank(); | ||
| 1254 | if (!cred) | ||
| 1255 | goto error_keyring; | ||
| 1256 | |||
| 1257 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | ||
| 1258 | keyring_r = NULL; | ||
| 1259 | |||
| 1260 | me = current; | ||
| 1261 | write_lock_irq(&tasklist_lock); | ||
| 1262 | |||
| 1263 | parent = me->real_parent; | ||
| 1264 | ret = -EPERM; | ||
| 1265 | |||
| 1266 | /* the parent mustn't be init and mustn't be a kernel thread */ | ||
| 1267 | if (parent->pid <= 1 || !parent->mm) | ||
| 1268 | goto not_permitted; | ||
| 1269 | |||
| 1270 | /* the parent must be single threaded */ | ||
| 1271 | if (atomic_read(&parent->signal->count) != 1) | ||
| 1272 | goto not_permitted; | ||
| 1273 | |||
| 1274 | /* the parent and the child must have different session keyrings or | ||
| 1275 | * there's no point */ | ||
| 1276 | mycred = current_cred(); | ||
| 1277 | pcred = __task_cred(parent); | ||
| 1278 | if (mycred == pcred || | ||
| 1279 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) | ||
| 1280 | goto already_same; | ||
| 1281 | |||
| 1282 | /* the parent must have the same effective ownership and mustn't be | ||
| 1283 | * SUID/SGID */ | ||
| 1284 | if (pcred-> uid != mycred->euid || | ||
| 1285 | pcred->euid != mycred->euid || | ||
| 1286 | pcred->suid != mycred->euid || | ||
| 1287 | pcred-> gid != mycred->egid || | ||
| 1288 | pcred->egid != mycred->egid || | ||
| 1289 | pcred->sgid != mycred->egid) | ||
| 1290 | goto not_permitted; | ||
| 1291 | |||
| 1292 | /* the keyrings must have the same UID */ | ||
| 1293 | if (pcred ->tgcred->session_keyring->uid != mycred->euid || | ||
| 1294 | mycred->tgcred->session_keyring->uid != mycred->euid) | ||
| 1295 | goto not_permitted; | ||
| 1296 | |||
| 1297 | /* the LSM must permit the replacement of the parent's keyring with the | ||
| 1298 | * keyring from this process */ | ||
| 1299 | ret = security_key_session_to_parent(mycred, pcred, | ||
| 1300 | key_ref_to_ptr(keyring_r)); | ||
| 1301 | if (ret < 0) | ||
| 1302 | goto not_permitted; | ||
| 1303 | |||
| 1304 | /* if there's an already pending keyring replacement, then we replace | ||
| 1305 | * that */ | ||
| 1306 | oldcred = parent->replacement_session_keyring; | ||
| 1307 | |||
| 1308 | /* the replacement session keyring is applied just prior to userspace | ||
| 1309 | * restarting */ | ||
| 1310 | parent->replacement_session_keyring = cred; | ||
| 1311 | cred = NULL; | ||
| 1312 | set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); | ||
| 1313 | |||
| 1314 | write_unlock_irq(&tasklist_lock); | ||
| 1315 | if (oldcred) | ||
| 1316 | put_cred(oldcred); | ||
| 1317 | return 0; | ||
| 1318 | |||
| 1319 | already_same: | ||
| 1320 | ret = 0; | ||
| 1321 | not_permitted: | ||
| 1322 | write_unlock_irq(&tasklist_lock); | ||
| 1323 | put_cred(cred); | ||
| 1324 | return ret; | ||
| 1325 | |||
| 1326 | error_keyring: | ||
| 1327 | key_ref_put(keyring_r); | ||
| 1328 | return ret; | ||
| 1329 | } | ||
| 1330 | |||
| 1216 | /*****************************************************************************/ | 1331 | /*****************************************************************************/ |
| 1217 | /* | 1332 | /* |
| 1218 | * the key control system call | 1333 | * the key control system call |
| @@ -1298,6 +1413,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1298 | (char __user *) arg3, | 1413 | (char __user *) arg3, |
| 1299 | (size_t) arg4); | 1414 | (size_t) arg4); |
| 1300 | 1415 | ||
| 1416 | case KEYCTL_SESSION_TO_PARENT: | ||
| 1417 | return keyctl_session_to_parent(); | ||
| 1418 | |||
| 1301 | default: | 1419 | default: |
| 1302 | return -EOPNOTSUPP; | 1420 | return -EOPNOTSUPP; |
| 1303 | } | 1421 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 3dba81c2eba3..8ec02746ca99 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -1000,3 +1000,102 @@ static void keyring_revoke(struct key *keyring) | |||
| 1000 | } | 1000 | } |
| 1001 | 1001 | ||
| 1002 | } /* end keyring_revoke() */ | 1002 | } /* end keyring_revoke() */ |
| 1003 | |||
| 1004 | /* | ||
| 1005 | * Determine whether a key is dead | ||
| 1006 | */ | ||
| 1007 | static bool key_is_dead(struct key *key, time_t limit) | ||
| 1008 | { | ||
| 1009 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
| 1010 | (key->expiry > 0 && key->expiry <= limit); | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | /* | ||
| 1014 | * Collect garbage from the contents of a keyring | ||
| 1015 | */ | ||
| 1016 | void keyring_gc(struct key *keyring, time_t limit) | ||
| 1017 | { | ||
| 1018 | struct keyring_list *klist, *new; | ||
| 1019 | struct key *key; | ||
| 1020 | int loop, keep, max; | ||
| 1021 | |||
| 1022 | kenter("{%x,%s}", key_serial(keyring), keyring->description); | ||
| 1023 | |||
| 1024 | down_write(&keyring->sem); | ||
| 1025 | |||
| 1026 | klist = keyring->payload.subscriptions; | ||
| 1027 | if (!klist) | ||
| 1028 | goto no_klist; | ||
| 1029 | |||
| 1030 | /* work out how many subscriptions we're keeping */ | ||
| 1031 | keep = 0; | ||
| 1032 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | ||
| 1033 | if (!key_is_dead(klist->keys[loop], limit)) | ||
| 1034 | keep++; | ||
| 1035 | |||
| 1036 | if (keep == klist->nkeys) | ||
| 1037 | goto just_return; | ||
| 1038 | |||
| 1039 | /* allocate a new keyring payload */ | ||
| 1040 | max = roundup(keep, 4); | ||
| 1041 | new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), | ||
| 1042 | GFP_KERNEL); | ||
| 1043 | if (!new) | ||
| 1044 | goto nomem; | ||
| 1045 | new->maxkeys = max; | ||
| 1046 | new->nkeys = 0; | ||
| 1047 | new->delkey = 0; | ||
| 1048 | |||
| 1049 | /* install the live keys | ||
| 1050 | * - must take care as expired keys may be updated back to life | ||
| 1051 | */ | ||
| 1052 | keep = 0; | ||
| 1053 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | ||
| 1054 | key = klist->keys[loop]; | ||
| 1055 | if (!key_is_dead(key, limit)) { | ||
| 1056 | if (keep >= max) | ||
| 1057 | goto discard_new; | ||
| 1058 | new->keys[keep++] = key_get(key); | ||
| 1059 | } | ||
| 1060 | } | ||
| 1061 | new->nkeys = keep; | ||
| 1062 | |||
| 1063 | /* adjust the quota */ | ||
| 1064 | key_payload_reserve(keyring, | ||
| 1065 | sizeof(struct keyring_list) + | ||
| 1066 | KEYQUOTA_LINK_BYTES * keep); | ||
| 1067 | |||
| 1068 | if (keep == 0) { | ||
| 1069 | rcu_assign_pointer(keyring->payload.subscriptions, NULL); | ||
| 1070 | kfree(new); | ||
| 1071 | } else { | ||
| 1072 | rcu_assign_pointer(keyring->payload.subscriptions, new); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | up_write(&keyring->sem); | ||
| 1076 | |||
| 1077 | call_rcu(&klist->rcu, keyring_clear_rcu_disposal); | ||
| 1078 | kleave(" [yes]"); | ||
| 1079 | return; | ||
| 1080 | |||
| 1081 | discard_new: | ||
| 1082 | new->nkeys = keep; | ||
| 1083 | keyring_clear_rcu_disposal(&new->rcu); | ||
| 1084 | up_write(&keyring->sem); | ||
| 1085 | kleave(" [discard]"); | ||
| 1086 | return; | ||
| 1087 | |||
| 1088 | just_return: | ||
| 1089 | up_write(&keyring->sem); | ||
| 1090 | kleave(" [no dead]"); | ||
| 1091 | return; | ||
| 1092 | |||
| 1093 | no_klist: | ||
| 1094 | up_write(&keyring->sem); | ||
| 1095 | kleave(" [no_klist]"); | ||
| 1096 | return; | ||
| 1097 | |||
| 1098 | nomem: | ||
| 1099 | up_write(&keyring->sem); | ||
| 1100 | kleave(" [oom]"); | ||
| 1101 | } | ||
diff --git a/security/keys/proc.c b/security/keys/proc.c index 769f9bdfd2b3..9d01021ca0c8 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
| @@ -91,59 +91,94 @@ __initcall(key_proc_init); | |||
| 91 | */ | 91 | */ |
| 92 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 92 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS |
| 93 | 93 | ||
| 94 | static struct rb_node *__key_serial_next(struct rb_node *n) | 94 | static struct rb_node *key_serial_next(struct rb_node *n) |
| 95 | { | 95 | { |
| 96 | struct user_namespace *user_ns = current_user_ns(); | ||
| 97 | |||
| 98 | n = rb_next(n); | ||
| 96 | while (n) { | 99 | while (n) { |
| 97 | struct key *key = rb_entry(n, struct key, serial_node); | 100 | struct key *key = rb_entry(n, struct key, serial_node); |
| 98 | if (key->user->user_ns == current_user_ns()) | 101 | if (key->user->user_ns == user_ns) |
| 99 | break; | 102 | break; |
| 100 | n = rb_next(n); | 103 | n = rb_next(n); |
| 101 | } | 104 | } |
| 102 | return n; | 105 | return n; |
| 103 | } | 106 | } |
| 104 | 107 | ||
| 105 | static struct rb_node *key_serial_next(struct rb_node *n) | 108 | static int proc_keys_open(struct inode *inode, struct file *file) |
| 106 | { | 109 | { |
| 107 | return __key_serial_next(rb_next(n)); | 110 | return seq_open(file, &proc_keys_ops); |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | static struct rb_node *key_serial_first(struct rb_root *r) | 113 | static struct key *find_ge_key(key_serial_t id) |
| 111 | { | 114 | { |
| 112 | struct rb_node *n = rb_first(r); | 115 | struct user_namespace *user_ns = current_user_ns(); |
| 113 | return __key_serial_next(n); | 116 | struct rb_node *n = key_serial_tree.rb_node; |
| 114 | } | 117 | struct key *minkey = NULL; |
| 115 | 118 | ||
| 116 | static int proc_keys_open(struct inode *inode, struct file *file) | 119 | while (n) { |
| 117 | { | 120 | struct key *key = rb_entry(n, struct key, serial_node); |
| 118 | return seq_open(file, &proc_keys_ops); | 121 | if (id < key->serial) { |
| 122 | if (!minkey || minkey->serial > key->serial) | ||
| 123 | minkey = key; | ||
| 124 | n = n->rb_left; | ||
| 125 | } else if (id > key->serial) { | ||
| 126 | n = n->rb_right; | ||
| 127 | } else { | ||
| 128 | minkey = key; | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | key = NULL; | ||
| 132 | } | ||
| 119 | 133 | ||
| 134 | if (!minkey) | ||
| 135 | return NULL; | ||
| 136 | |||
| 137 | for (;;) { | ||
| 138 | if (minkey->user->user_ns == user_ns) | ||
| 139 | return minkey; | ||
| 140 | n = rb_next(&minkey->serial_node); | ||
| 141 | if (!n) | ||
| 142 | return NULL; | ||
| 143 | minkey = rb_entry(n, struct key, serial_node); | ||
| 144 | } | ||
| 120 | } | 145 | } |
| 121 | 146 | ||
| 122 | static void *proc_keys_start(struct seq_file *p, loff_t *_pos) | 147 | static void *proc_keys_start(struct seq_file *p, loff_t *_pos) |
| 148 | __acquires(key_serial_lock) | ||
| 123 | { | 149 | { |
| 124 | struct rb_node *_p; | 150 | key_serial_t pos = *_pos; |
| 125 | loff_t pos = *_pos; | 151 | struct key *key; |
| 126 | 152 | ||
| 127 | spin_lock(&key_serial_lock); | 153 | spin_lock(&key_serial_lock); |
| 128 | 154 | ||
| 129 | _p = key_serial_first(&key_serial_tree); | 155 | if (*_pos > INT_MAX) |
| 130 | while (pos > 0 && _p) { | 156 | return NULL; |
| 131 | pos--; | 157 | key = find_ge_key(pos); |
| 132 | _p = key_serial_next(_p); | 158 | if (!key) |
| 133 | } | 159 | return NULL; |
| 134 | 160 | *_pos = key->serial; | |
| 135 | return _p; | 161 | return &key->serial_node; |
| 162 | } | ||
| 136 | 163 | ||
| 164 | static inline key_serial_t key_node_serial(struct rb_node *n) | ||
| 165 | { | ||
| 166 | struct key *key = rb_entry(n, struct key, serial_node); | ||
| 167 | return key->serial; | ||
| 137 | } | 168 | } |
| 138 | 169 | ||
| 139 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) | 170 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) |
| 140 | { | 171 | { |
| 141 | (*_pos)++; | 172 | struct rb_node *n; |
| 142 | return key_serial_next((struct rb_node *) v); | ||
| 143 | 173 | ||
| 174 | n = key_serial_next(v); | ||
| 175 | if (n) | ||
| 176 | *_pos = key_node_serial(n); | ||
| 177 | return n; | ||
| 144 | } | 178 | } |
| 145 | 179 | ||
| 146 | static void proc_keys_stop(struct seq_file *p, void *v) | 180 | static void proc_keys_stop(struct seq_file *p, void *v) |
| 181 | __releases(key_serial_lock) | ||
| 147 | { | 182 | { |
| 148 | spin_unlock(&key_serial_lock); | 183 | spin_unlock(&key_serial_lock); |
| 149 | } | 184 | } |
| @@ -174,11 +209,9 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
| 174 | /* come up with a suitable timeout value */ | 209 | /* come up with a suitable timeout value */ |
| 175 | if (key->expiry == 0) { | 210 | if (key->expiry == 0) { |
| 176 | memcpy(xbuf, "perm", 5); | 211 | memcpy(xbuf, "perm", 5); |
| 177 | } | 212 | } else if (now.tv_sec >= key->expiry) { |
| 178 | else if (now.tv_sec >= key->expiry) { | ||
| 179 | memcpy(xbuf, "expd", 5); | 213 | memcpy(xbuf, "expd", 5); |
| 180 | } | 214 | } else { |
| 181 | else { | ||
| 182 | timo = key->expiry - now.tv_sec; | 215 | timo = key->expiry - now.tv_sec; |
| 183 | 216 | ||
| 184 | if (timo < 60) | 217 | if (timo < 60) |
| @@ -218,9 +251,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
| 218 | seq_putc(m, '\n'); | 251 | seq_putc(m, '\n'); |
| 219 | 252 | ||
| 220 | rcu_read_unlock(); | 253 | rcu_read_unlock(); |
| 221 | |||
| 222 | return 0; | 254 | return 0; |
| 223 | |||
| 224 | } | 255 | } |
| 225 | 256 | ||
| 226 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ | 257 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ |
| @@ -246,6 +277,7 @@ static struct rb_node *key_user_first(struct rb_root *r) | |||
| 246 | struct rb_node *n = rb_first(r); | 277 | struct rb_node *n = rb_first(r); |
| 247 | return __key_user_next(n); | 278 | return __key_user_next(n); |
| 248 | } | 279 | } |
| 280 | |||
| 249 | /*****************************************************************************/ | 281 | /*****************************************************************************/ |
| 250 | /* | 282 | /* |
| 251 | * implement "/proc/key-users" to provides a list of the key users | 283 | * implement "/proc/key-users" to provides a list of the key users |
| @@ -253,10 +285,10 @@ static struct rb_node *key_user_first(struct rb_root *r) | |||
| 253 | static int proc_key_users_open(struct inode *inode, struct file *file) | 285 | static int proc_key_users_open(struct inode *inode, struct file *file) |
| 254 | { | 286 | { |
| 255 | return seq_open(file, &proc_key_users_ops); | 287 | return seq_open(file, &proc_key_users_ops); |
| 256 | |||
| 257 | } | 288 | } |
| 258 | 289 | ||
| 259 | static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | 290 | static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) |
| 291 | __acquires(key_user_lock) | ||
| 260 | { | 292 | { |
| 261 | struct rb_node *_p; | 293 | struct rb_node *_p; |
| 262 | loff_t pos = *_pos; | 294 | loff_t pos = *_pos; |
| @@ -270,17 +302,16 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | |||
| 270 | } | 302 | } |
| 271 | 303 | ||
| 272 | return _p; | 304 | return _p; |
| 273 | |||
| 274 | } | 305 | } |
| 275 | 306 | ||
| 276 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) | 307 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) |
| 277 | { | 308 | { |
| 278 | (*_pos)++; | 309 | (*_pos)++; |
| 279 | return key_user_next((struct rb_node *) v); | 310 | return key_user_next((struct rb_node *) v); |
| 280 | |||
| 281 | } | 311 | } |
| 282 | 312 | ||
| 283 | static void proc_key_users_stop(struct seq_file *p, void *v) | 313 | static void proc_key_users_stop(struct seq_file *p, void *v) |
| 314 | __releases(key_user_lock) | ||
| 284 | { | 315 | { |
| 285 | spin_unlock(&key_user_lock); | 316 | spin_unlock(&key_user_lock); |
| 286 | } | 317 | } |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 276d27882ce8..5c23afb31ece 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/security.h> | ||
| 20 | #include <linux/user_namespace.h> | 21 | #include <linux/user_namespace.h> |
| 21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 22 | #include "internal.h" | 23 | #include "internal.h" |
| @@ -487,7 +488,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target) | |||
| 487 | * - don't create special keyrings unless so requested | 488 | * - don't create special keyrings unless so requested |
| 488 | * - partially constructed keys aren't found unless requested | 489 | * - partially constructed keys aren't found unless requested |
| 489 | */ | 490 | */ |
| 490 | key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 491 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, |
| 491 | key_perm_t perm) | 492 | key_perm_t perm) |
| 492 | { | 493 | { |
| 493 | struct request_key_auth *rka; | 494 | struct request_key_auth *rka; |
| @@ -503,7 +504,7 @@ try_again: | |||
| 503 | switch (id) { | 504 | switch (id) { |
| 504 | case KEY_SPEC_THREAD_KEYRING: | 505 | case KEY_SPEC_THREAD_KEYRING: |
| 505 | if (!cred->thread_keyring) { | 506 | if (!cred->thread_keyring) { |
| 506 | if (!create) | 507 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 507 | goto error; | 508 | goto error; |
| 508 | 509 | ||
| 509 | ret = install_thread_keyring(); | 510 | ret = install_thread_keyring(); |
| @@ -521,7 +522,7 @@ try_again: | |||
| 521 | 522 | ||
| 522 | case KEY_SPEC_PROCESS_KEYRING: | 523 | case KEY_SPEC_PROCESS_KEYRING: |
| 523 | if (!cred->tgcred->process_keyring) { | 524 | if (!cred->tgcred->process_keyring) { |
| 524 | if (!create) | 525 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 525 | goto error; | 526 | goto error; |
| 526 | 527 | ||
| 527 | ret = install_process_keyring(); | 528 | ret = install_process_keyring(); |
| @@ -642,7 +643,14 @@ try_again: | |||
| 642 | break; | 643 | break; |
| 643 | } | 644 | } |
| 644 | 645 | ||
| 645 | if (!partial) { | 646 | /* unlink does not use the nominated key in any way, so can skip all |
| 647 | * the permission checks as it is only concerned with the keyring */ | ||
| 648 | if (lflags & KEY_LOOKUP_FOR_UNLINK) { | ||
| 649 | ret = 0; | ||
| 650 | goto error; | ||
| 651 | } | ||
| 652 | |||
| 653 | if (!(lflags & KEY_LOOKUP_PARTIAL)) { | ||
| 646 | ret = wait_for_key_construction(key, true); | 654 | ret = wait_for_key_construction(key, true); |
| 647 | switch (ret) { | 655 | switch (ret) { |
| 648 | case -ERESTARTSYS: | 656 | case -ERESTARTSYS: |
| @@ -660,7 +668,8 @@ try_again: | |||
| 660 | } | 668 | } |
| 661 | 669 | ||
| 662 | ret = -EIO; | 670 | ret = -EIO; |
| 663 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 671 | if (!(lflags & KEY_LOOKUP_PARTIAL) && |
| 672 | !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | ||
| 664 | goto invalid_key; | 673 | goto invalid_key; |
| 665 | 674 | ||
| 666 | /* check the permissions */ | 675 | /* check the permissions */ |
| @@ -702,7 +711,7 @@ long join_session_keyring(const char *name) | |||
| 702 | /* only permit this if there's a single thread in the thread group - | 711 | /* only permit this if there's a single thread in the thread group - |
| 703 | * this avoids us having to adjust the creds on all threads and risking | 712 | * this avoids us having to adjust the creds on all threads and risking |
| 704 | * ENOMEM */ | 713 | * ENOMEM */ |
| 705 | if (!is_single_threaded(current)) | 714 | if (!current_is_single_threaded()) |
| 706 | return -EMLINK; | 715 | return -EMLINK; |
| 707 | 716 | ||
| 708 | new = prepare_creds(); | 717 | new = prepare_creds(); |
| @@ -760,3 +769,51 @@ error: | |||
| 760 | abort_creds(new); | 769 | abort_creds(new); |
| 761 | return ret; | 770 | return ret; |
| 762 | } | 771 | } |
| 772 | |||
| 773 | /* | ||
| 774 | * Replace a process's session keyring when that process resumes userspace on | ||
| 775 | * behalf of one of its children | ||
| 776 | */ | ||
| 777 | void key_replace_session_keyring(void) | ||
| 778 | { | ||
| 779 | const struct cred *old; | ||
| 780 | struct cred *new; | ||
| 781 | |||
| 782 | if (!current->replacement_session_keyring) | ||
| 783 | return; | ||
| 784 | |||
| 785 | write_lock_irq(&tasklist_lock); | ||
| 786 | new = current->replacement_session_keyring; | ||
| 787 | current->replacement_session_keyring = NULL; | ||
| 788 | write_unlock_irq(&tasklist_lock); | ||
| 789 | |||
| 790 | if (!new) | ||
| 791 | return; | ||
| 792 | |||
| 793 | old = current_cred(); | ||
| 794 | new-> uid = old-> uid; | ||
| 795 | new-> euid = old-> euid; | ||
| 796 | new-> suid = old-> suid; | ||
| 797 | new->fsuid = old->fsuid; | ||
| 798 | new-> gid = old-> gid; | ||
| 799 | new-> egid = old-> egid; | ||
| 800 | new-> sgid = old-> sgid; | ||
| 801 | new->fsgid = old->fsgid; | ||
| 802 | new->user = get_uid(old->user); | ||
| 803 | new->group_info = get_group_info(old->group_info); | ||
| 804 | |||
| 805 | new->securebits = old->securebits; | ||
| 806 | new->cap_inheritable = old->cap_inheritable; | ||
| 807 | new->cap_permitted = old->cap_permitted; | ||
| 808 | new->cap_effective = old->cap_effective; | ||
| 809 | new->cap_bset = old->cap_bset; | ||
| 810 | |||
| 811 | new->jit_keyring = old->jit_keyring; | ||
| 812 | new->thread_keyring = key_get(old->thread_keyring); | ||
| 813 | new->tgcred->tgid = old->tgcred->tgid; | ||
| 814 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
| 815 | |||
| 816 | security_transfer_creds(new, old); | ||
| 817 | |||
| 818 | commit_creds(new); | ||
| 819 | } | ||
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index b611d493c2d8..5e05dc09e2db 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c | |||
| @@ -13,6 +13,8 @@ | |||
| 13 | #include <linux/sysctl.h> | 13 | #include <linux/sysctl.h> |
| 14 | #include "internal.h" | 14 | #include "internal.h" |
| 15 | 15 | ||
| 16 | static const int zero, one = 1, max = INT_MAX; | ||
| 17 | |||
| 16 | ctl_table key_sysctls[] = { | 18 | ctl_table key_sysctls[] = { |
| 17 | { | 19 | { |
| 18 | .ctl_name = CTL_UNNUMBERED, | 20 | .ctl_name = CTL_UNNUMBERED, |
| @@ -20,7 +22,9 @@ ctl_table key_sysctls[] = { | |||
| 20 | .data = &key_quota_maxkeys, | 22 | .data = &key_quota_maxkeys, |
| 21 | .maxlen = sizeof(unsigned), | 23 | .maxlen = sizeof(unsigned), |
| 22 | .mode = 0644, | 24 | .mode = 0644, |
| 23 | .proc_handler = &proc_dointvec, | 25 | .proc_handler = &proc_dointvec_minmax, |
| 26 | .extra1 = (void *) &one, | ||
| 27 | .extra2 = (void *) &max, | ||
| 24 | }, | 28 | }, |
| 25 | { | 29 | { |
| 26 | .ctl_name = CTL_UNNUMBERED, | 30 | .ctl_name = CTL_UNNUMBERED, |
| @@ -28,7 +32,9 @@ ctl_table key_sysctls[] = { | |||
| 28 | .data = &key_quota_maxbytes, | 32 | .data = &key_quota_maxbytes, |
| 29 | .maxlen = sizeof(unsigned), | 33 | .maxlen = sizeof(unsigned), |
| 30 | .mode = 0644, | 34 | .mode = 0644, |
| 31 | .proc_handler = &proc_dointvec, | 35 | .proc_handler = &proc_dointvec_minmax, |
| 36 | .extra1 = (void *) &one, | ||
| 37 | .extra2 = (void *) &max, | ||
| 32 | }, | 38 | }, |
| 33 | { | 39 | { |
| 34 | .ctl_name = CTL_UNNUMBERED, | 40 | .ctl_name = CTL_UNNUMBERED, |
| @@ -36,7 +42,9 @@ ctl_table key_sysctls[] = { | |||
| 36 | .data = &key_quota_root_maxkeys, | 42 | .data = &key_quota_root_maxkeys, |
| 37 | .maxlen = sizeof(unsigned), | 43 | .maxlen = sizeof(unsigned), |
| 38 | .mode = 0644, | 44 | .mode = 0644, |
| 39 | .proc_handler = &proc_dointvec, | 45 | .proc_handler = &proc_dointvec_minmax, |
| 46 | .extra1 = (void *) &one, | ||
| 47 | .extra2 = (void *) &max, | ||
| 40 | }, | 48 | }, |
| 41 | { | 49 | { |
| 42 | .ctl_name = CTL_UNNUMBERED, | 50 | .ctl_name = CTL_UNNUMBERED, |
| @@ -44,7 +52,19 @@ ctl_table key_sysctls[] = { | |||
| 44 | .data = &key_quota_root_maxbytes, | 52 | .data = &key_quota_root_maxbytes, |
| 45 | .maxlen = sizeof(unsigned), | 53 | .maxlen = sizeof(unsigned), |
| 46 | .mode = 0644, | 54 | .mode = 0644, |
| 47 | .proc_handler = &proc_dointvec, | 55 | .proc_handler = &proc_dointvec_minmax, |
| 56 | .extra1 = (void *) &one, | ||
| 57 | .extra2 = (void *) &max, | ||
| 58 | }, | ||
| 59 | { | ||
| 60 | .ctl_name = CTL_UNNUMBERED, | ||
| 61 | .procname = "gc_delay", | ||
| 62 | .data = &key_gc_delay, | ||
| 63 | .maxlen = sizeof(unsigned), | ||
| 64 | .mode = 0644, | ||
| 65 | .proc_handler = &proc_dointvec_minmax, | ||
| 66 | .extra1 = (void *) &zero, | ||
| 67 | .extra2 = (void *) &max, | ||
| 48 | }, | 68 | }, |
| 49 | { .ctl_name = 0 } | 69 | { .ctl_name = 0 } |
| 50 | }; | 70 | }; |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 94b868494b31..3bb90b6f1dd3 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
| @@ -187,7 +187,7 @@ static inline void print_ipv6_addr(struct audit_buffer *ab, | |||
| 187 | char *name1, char *name2) | 187 | char *name1, char *name2) |
| 188 | { | 188 | { |
| 189 | if (!ipv6_addr_any(addr)) | 189 | if (!ipv6_addr_any(addr)) |
| 190 | audit_log_format(ab, " %s=%pI6", name1, addr); | 190 | audit_log_format(ab, " %s=%pI6c", name1, addr); |
| 191 | if (port) | 191 | if (port) |
| 192 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 192 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); |
| 193 | } | 193 | } |
| @@ -220,6 +220,8 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | switch (a->type) { | 222 | switch (a->type) { |
| 223 | case LSM_AUDIT_NO_AUDIT: | ||
| 224 | return; | ||
| 223 | case LSM_AUDIT_DATA_IPC: | 225 | case LSM_AUDIT_DATA_IPC: |
| 224 | audit_log_format(ab, " key=%d ", a->u.ipc_id); | 226 | audit_log_format(ab, " key=%d ", a->u.ipc_id); |
| 225 | break; | 227 | break; |
diff --git a/security/min_addr.c b/security/min_addr.c new file mode 100644 index 000000000000..c844eed7915d --- /dev/null +++ b/security/min_addr.c | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #include <linux/init.h> | ||
| 2 | #include <linux/mm.h> | ||
| 3 | #include <linux/security.h> | ||
| 4 | #include <linux/sysctl.h> | ||
| 5 | |||
| 6 | /* amount of vm to protect from userspace access by both DAC and the LSM*/ | ||
| 7 | unsigned long mmap_min_addr; | ||
| 8 | /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */ | ||
| 9 | unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; | ||
| 10 | /* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */ | ||
| 11 | |||
| 12 | /* | ||
| 13 | * Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR) | ||
| 14 | */ | ||
| 15 | static void update_mmap_min_addr(void) | ||
| 16 | { | ||
| 17 | #ifdef CONFIG_LSM_MMAP_MIN_ADDR | ||
| 18 | if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR) | ||
| 19 | mmap_min_addr = dac_mmap_min_addr; | ||
| 20 | else | ||
| 21 | mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR; | ||
| 22 | #else | ||
| 23 | mmap_min_addr = dac_mmap_min_addr; | ||
| 24 | #endif | ||
| 25 | } | ||
| 26 | |||
| 27 | /* | ||
| 28 | * sysctl handler which just sets dac_mmap_min_addr = the new value and then | ||
| 29 | * calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly | ||
| 30 | */ | ||
| 31 | int mmap_min_addr_handler(struct ctl_table *table, int write, | ||
| 32 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 33 | { | ||
| 34 | int ret; | ||
| 35 | |||
| 36 | ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos); | ||
| 37 | |||
| 38 | update_mmap_min_addr(); | ||
| 39 | |||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | int __init init_mmap_min_addr(void) | ||
| 44 | { | ||
| 45 | update_mmap_min_addr(); | ||
| 46 | |||
| 47 | return 0; | ||
| 48 | } | ||
| 49 | pure_initcall(init_mmap_min_addr); | ||
diff --git a/security/security.c b/security/security.c index dc7674fbfc7a..c4c673240c1c 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -124,9 +124,9 @@ int register_security(struct security_operations *ops) | |||
| 124 | 124 | ||
| 125 | /* Security operations */ | 125 | /* Security operations */ |
| 126 | 126 | ||
| 127 | int security_ptrace_may_access(struct task_struct *child, unsigned int mode) | 127 | int security_ptrace_access_check(struct task_struct *child, unsigned int mode) |
| 128 | { | 128 | { |
| 129 | return security_ops->ptrace_may_access(child, mode); | 129 | return security_ops->ptrace_access_check(child, mode); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | int security_ptrace_traceme(struct task_struct *parent) | 132 | int security_ptrace_traceme(struct task_struct *parent) |
| @@ -684,6 +684,11 @@ int security_task_create(unsigned long clone_flags) | |||
| 684 | return security_ops->task_create(clone_flags); | 684 | return security_ops->task_create(clone_flags); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 688 | { | ||
| 689 | return security_ops->cred_alloc_blank(cred, gfp); | ||
| 690 | } | ||
| 691 | |||
| 687 | void security_cred_free(struct cred *cred) | 692 | void security_cred_free(struct cred *cred) |
| 688 | { | 693 | { |
| 689 | security_ops->cred_free(cred); | 694 | security_ops->cred_free(cred); |
| @@ -699,6 +704,11 @@ void security_commit_creds(struct cred *new, const struct cred *old) | |||
| 699 | security_ops->cred_commit(new, old); | 704 | security_ops->cred_commit(new, old); |
| 700 | } | 705 | } |
| 701 | 706 | ||
| 707 | void security_transfer_creds(struct cred *new, const struct cred *old) | ||
| 708 | { | ||
| 709 | security_ops->cred_transfer(new, old); | ||
| 710 | } | ||
| 711 | |||
| 702 | int security_kernel_act_as(struct cred *new, u32 secid) | 712 | int security_kernel_act_as(struct cred *new, u32 secid) |
| 703 | { | 713 | { |
| 704 | return security_ops->kernel_act_as(new, secid); | 714 | return security_ops->kernel_act_as(new, secid); |
| @@ -709,6 +719,11 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 709 | return security_ops->kernel_create_files_as(new, inode); | 719 | return security_ops->kernel_create_files_as(new, inode); |
| 710 | } | 720 | } |
| 711 | 721 | ||
| 722 | int security_kernel_module_request(void) | ||
| 723 | { | ||
| 724 | return security_ops->kernel_module_request(); | ||
| 725 | } | ||
| 726 | |||
| 712 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 727 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 713 | { | 728 | { |
| 714 | return security_ops->task_setuid(id0, id1, id2, flags); | 729 | return security_ops->task_setuid(id0, id1, id2, flags); |
| @@ -959,6 +974,24 @@ void security_release_secctx(char *secdata, u32 seclen) | |||
| 959 | } | 974 | } |
| 960 | EXPORT_SYMBOL(security_release_secctx); | 975 | EXPORT_SYMBOL(security_release_secctx); |
| 961 | 976 | ||
| 977 | int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 978 | { | ||
| 979 | return security_ops->inode_notifysecctx(inode, ctx, ctxlen); | ||
| 980 | } | ||
| 981 | EXPORT_SYMBOL(security_inode_notifysecctx); | ||
| 982 | |||
| 983 | int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 984 | { | ||
| 985 | return security_ops->inode_setsecctx(dentry, ctx, ctxlen); | ||
| 986 | } | ||
| 987 | EXPORT_SYMBOL(security_inode_setsecctx); | ||
| 988 | |||
| 989 | int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 990 | { | ||
| 991 | return security_ops->inode_getsecctx(inode, ctx, ctxlen); | ||
| 992 | } | ||
| 993 | EXPORT_SYMBOL(security_inode_getsecctx); | ||
| 994 | |||
| 962 | #ifdef CONFIG_SECURITY_NETWORK | 995 | #ifdef CONFIG_SECURITY_NETWORK |
| 963 | 996 | ||
| 964 | int security_unix_stream_connect(struct socket *sock, struct socket *other, | 997 | int security_unix_stream_connect(struct socket *sock, struct socket *other, |
| @@ -1112,6 +1145,24 @@ void security_inet_conn_established(struct sock *sk, | |||
| 1112 | security_ops->inet_conn_established(sk, skb); | 1145 | security_ops->inet_conn_established(sk, skb); |
| 1113 | } | 1146 | } |
| 1114 | 1147 | ||
| 1148 | int security_tun_dev_create(void) | ||
| 1149 | { | ||
| 1150 | return security_ops->tun_dev_create(); | ||
| 1151 | } | ||
| 1152 | EXPORT_SYMBOL(security_tun_dev_create); | ||
| 1153 | |||
| 1154 | void security_tun_dev_post_create(struct sock *sk) | ||
| 1155 | { | ||
| 1156 | return security_ops->tun_dev_post_create(sk); | ||
| 1157 | } | ||
| 1158 | EXPORT_SYMBOL(security_tun_dev_post_create); | ||
| 1159 | |||
| 1160 | int security_tun_dev_attach(struct sock *sk) | ||
| 1161 | { | ||
| 1162 | return security_ops->tun_dev_attach(sk); | ||
| 1163 | } | ||
| 1164 | EXPORT_SYMBOL(security_tun_dev_attach); | ||
| 1165 | |||
| 1115 | #endif /* CONFIG_SECURITY_NETWORK */ | 1166 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1116 | 1167 | ||
| 1117 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1168 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| @@ -1218,6 +1269,13 @@ int security_key_getsecurity(struct key *key, char **_buffer) | |||
| 1218 | return security_ops->key_getsecurity(key, _buffer); | 1269 | return security_ops->key_getsecurity(key, _buffer); |
| 1219 | } | 1270 | } |
| 1220 | 1271 | ||
| 1272 | int security_key_session_to_parent(const struct cred *cred, | ||
| 1273 | const struct cred *parent_cred, | ||
| 1274 | struct key *key) | ||
| 1275 | { | ||
| 1276 | return security_ops->key_session_to_parent(cred, parent_cred, key); | ||
| 1277 | } | ||
| 1278 | |||
| 1221 | #endif /* CONFIG_KEYS */ | 1279 | #endif /* CONFIG_KEYS */ |
| 1222 | 1280 | ||
| 1223 | #ifdef CONFIG_AUDIT | 1281 | #ifdef CONFIG_AUDIT |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index b2ab60859832..b4b5da1c0a42 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | |||
| 137 | * @tclass: target security class | 137 | * @tclass: target security class |
| 138 | * @av: access vector | 138 | * @av: access vector |
| 139 | */ | 139 | */ |
| 140 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | 140 | static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) |
| 141 | { | 141 | { |
| 142 | const char **common_pts = NULL; | 142 | const char **common_pts = NULL; |
| 143 | u32 common_base = 0; | 143 | u32 common_base = 0; |
| @@ -492,23 +492,35 @@ out: | |||
| 492 | return node; | 492 | return node; |
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | static inline void avc_print_ipv6_addr(struct audit_buffer *ab, | 495 | /** |
| 496 | struct in6_addr *addr, __be16 port, | 496 | * avc_audit_pre_callback - SELinux specific information |
| 497 | char *name1, char *name2) | 497 | * will be called by generic audit code |
| 498 | * @ab: the audit buffer | ||
| 499 | * @a: audit_data | ||
| 500 | */ | ||
| 501 | static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | ||
| 498 | { | 502 | { |
| 499 | if (!ipv6_addr_any(addr)) | 503 | struct common_audit_data *ad = a; |
| 500 | audit_log_format(ab, " %s=%pI6", name1, addr); | 504 | audit_log_format(ab, "avc: %s ", |
| 501 | if (port) | 505 | ad->selinux_audit_data.denied ? "denied" : "granted"); |
| 502 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 506 | avc_dump_av(ab, ad->selinux_audit_data.tclass, |
| 507 | ad->selinux_audit_data.audited); | ||
| 508 | audit_log_format(ab, " for "); | ||
| 503 | } | 509 | } |
| 504 | 510 | ||
| 505 | static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | 511 | /** |
| 506 | __be16 port, char *name1, char *name2) | 512 | * avc_audit_post_callback - SELinux specific information |
| 513 | * will be called by generic audit code | ||
| 514 | * @ab: the audit buffer | ||
| 515 | * @a: audit_data | ||
| 516 | */ | ||
| 517 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | ||
| 507 | { | 518 | { |
| 508 | if (addr) | 519 | struct common_audit_data *ad = a; |
| 509 | audit_log_format(ab, " %s=%pI4", name1, &addr); | 520 | audit_log_format(ab, " "); |
| 510 | if (port) | 521 | avc_dump_query(ab, ad->selinux_audit_data.ssid, |
| 511 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 522 | ad->selinux_audit_data.tsid, |
| 523 | ad->selinux_audit_data.tclass); | ||
| 512 | } | 524 | } |
| 513 | 525 | ||
| 514 | /** | 526 | /** |
| @@ -532,13 +544,10 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | |||
| 532 | */ | 544 | */ |
| 533 | void avc_audit(u32 ssid, u32 tsid, | 545 | void avc_audit(u32 ssid, u32 tsid, |
| 534 | u16 tclass, u32 requested, | 546 | u16 tclass, u32 requested, |
| 535 | struct av_decision *avd, int result, struct avc_audit_data *a) | 547 | struct av_decision *avd, int result, struct common_audit_data *a) |
| 536 | { | 548 | { |
| 537 | struct task_struct *tsk = current; | 549 | struct common_audit_data stack_data; |
| 538 | struct inode *inode = NULL; | ||
| 539 | u32 denied, audited; | 550 | u32 denied, audited; |
| 540 | struct audit_buffer *ab; | ||
| 541 | |||
| 542 | denied = requested & ~avd->allowed; | 551 | denied = requested & ~avd->allowed; |
| 543 | if (denied) { | 552 | if (denied) { |
| 544 | audited = denied; | 553 | audited = denied; |
| @@ -551,144 +560,20 @@ void avc_audit(u32 ssid, u32 tsid, | |||
| 551 | if (!(audited & avd->auditallow)) | 560 | if (!(audited & avd->auditallow)) |
| 552 | return; | 561 | return; |
| 553 | } | 562 | } |
| 554 | 563 | if (!a) { | |
| 555 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); | 564 | a = &stack_data; |
| 556 | if (!ab) | 565 | memset(a, 0, sizeof(*a)); |
| 557 | return; /* audit_panic has been called */ | 566 | a->type = LSM_AUDIT_NO_AUDIT; |
| 558 | audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); | ||
| 559 | avc_dump_av(ab, tclass, audited); | ||
| 560 | audit_log_format(ab, " for "); | ||
| 561 | if (a && a->tsk) | ||
| 562 | tsk = a->tsk; | ||
| 563 | if (tsk && tsk->pid) { | ||
| 564 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
| 565 | audit_log_untrustedstring(ab, tsk->comm); | ||
| 566 | } | 567 | } |
| 567 | if (a) { | 568 | a->selinux_audit_data.tclass = tclass; |
| 568 | switch (a->type) { | 569 | a->selinux_audit_data.requested = requested; |
| 569 | case AVC_AUDIT_DATA_IPC: | 570 | a->selinux_audit_data.ssid = ssid; |
| 570 | audit_log_format(ab, " key=%d", a->u.ipc_id); | 571 | a->selinux_audit_data.tsid = tsid; |
| 571 | break; | 572 | a->selinux_audit_data.audited = audited; |
| 572 | case AVC_AUDIT_DATA_CAP: | 573 | a->selinux_audit_data.denied = denied; |
| 573 | audit_log_format(ab, " capability=%d", a->u.cap); | 574 | a->lsm_pre_audit = avc_audit_pre_callback; |
| 574 | break; | 575 | a->lsm_post_audit = avc_audit_post_callback; |
| 575 | case AVC_AUDIT_DATA_FS: | 576 | common_lsm_audit(a); |
| 576 | if (a->u.fs.path.dentry) { | ||
| 577 | struct dentry *dentry = a->u.fs.path.dentry; | ||
| 578 | if (a->u.fs.path.mnt) { | ||
| 579 | audit_log_d_path(ab, "path=", | ||
| 580 | &a->u.fs.path); | ||
| 581 | } else { | ||
| 582 | audit_log_format(ab, " name="); | ||
| 583 | audit_log_untrustedstring(ab, dentry->d_name.name); | ||
| 584 | } | ||
| 585 | inode = dentry->d_inode; | ||
| 586 | } else if (a->u.fs.inode) { | ||
| 587 | struct dentry *dentry; | ||
| 588 | inode = a->u.fs.inode; | ||
| 589 | dentry = d_find_alias(inode); | ||
| 590 | if (dentry) { | ||
| 591 | audit_log_format(ab, " name="); | ||
| 592 | audit_log_untrustedstring(ab, dentry->d_name.name); | ||
| 593 | dput(dentry); | ||
| 594 | } | ||
| 595 | } | ||
| 596 | if (inode) | ||
| 597 | audit_log_format(ab, " dev=%s ino=%lu", | ||
| 598 | inode->i_sb->s_id, | ||
| 599 | inode->i_ino); | ||
| 600 | break; | ||
| 601 | case AVC_AUDIT_DATA_NET: | ||
| 602 | if (a->u.net.sk) { | ||
| 603 | struct sock *sk = a->u.net.sk; | ||
| 604 | struct unix_sock *u; | ||
| 605 | int len = 0; | ||
| 606 | char *p = NULL; | ||
| 607 | |||
| 608 | switch (sk->sk_family) { | ||
| 609 | case AF_INET: { | ||
| 610 | struct inet_sock *inet = inet_sk(sk); | ||
| 611 | |||
| 612 | avc_print_ipv4_addr(ab, inet->rcv_saddr, | ||
| 613 | inet->sport, | ||
| 614 | "laddr", "lport"); | ||
| 615 | avc_print_ipv4_addr(ab, inet->daddr, | ||
| 616 | inet->dport, | ||
| 617 | "faddr", "fport"); | ||
| 618 | break; | ||
| 619 | } | ||
| 620 | case AF_INET6: { | ||
| 621 | struct inet_sock *inet = inet_sk(sk); | ||
| 622 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | ||
| 623 | |||
| 624 | avc_print_ipv6_addr(ab, &inet6->rcv_saddr, | ||
| 625 | inet->sport, | ||
| 626 | "laddr", "lport"); | ||
| 627 | avc_print_ipv6_addr(ab, &inet6->daddr, | ||
| 628 | inet->dport, | ||
| 629 | "faddr", "fport"); | ||
| 630 | break; | ||
| 631 | } | ||
| 632 | case AF_UNIX: | ||
| 633 | u = unix_sk(sk); | ||
| 634 | if (u->dentry) { | ||
| 635 | struct path path = { | ||
| 636 | .dentry = u->dentry, | ||
| 637 | .mnt = u->mnt | ||
| 638 | }; | ||
| 639 | audit_log_d_path(ab, "path=", | ||
| 640 | &path); | ||
| 641 | break; | ||
| 642 | } | ||
| 643 | if (!u->addr) | ||
| 644 | break; | ||
| 645 | len = u->addr->len-sizeof(short); | ||
| 646 | p = &u->addr->name->sun_path[0]; | ||
| 647 | audit_log_format(ab, " path="); | ||
| 648 | if (*p) | ||
| 649 | audit_log_untrustedstring(ab, p); | ||
| 650 | else | ||
| 651 | audit_log_n_hex(ab, p, len); | ||
| 652 | break; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | switch (a->u.net.family) { | ||
| 657 | case AF_INET: | ||
| 658 | avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, | ||
| 659 | a->u.net.sport, | ||
| 660 | "saddr", "src"); | ||
| 661 | avc_print_ipv4_addr(ab, a->u.net.v4info.daddr, | ||
| 662 | a->u.net.dport, | ||
| 663 | "daddr", "dest"); | ||
| 664 | break; | ||
| 665 | case AF_INET6: | ||
| 666 | avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr, | ||
| 667 | a->u.net.sport, | ||
| 668 | "saddr", "src"); | ||
| 669 | avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr, | ||
| 670 | a->u.net.dport, | ||
| 671 | "daddr", "dest"); | ||
| 672 | break; | ||
| 673 | } | ||
| 674 | if (a->u.net.netif > 0) { | ||
| 675 | struct net_device *dev; | ||
| 676 | |||
| 677 | /* NOTE: we always use init's namespace */ | ||
| 678 | dev = dev_get_by_index(&init_net, | ||
| 679 | a->u.net.netif); | ||
| 680 | if (dev) { | ||
| 681 | audit_log_format(ab, " netif=%s", | ||
| 682 | dev->name); | ||
| 683 | dev_put(dev); | ||
| 684 | } | ||
| 685 | } | ||
| 686 | break; | ||
| 687 | } | ||
| 688 | } | ||
| 689 | audit_log_format(ab, " "); | ||
| 690 | avc_dump_query(ab, ssid, tsid, tclass); | ||
| 691 | audit_log_end(ab); | ||
| 692 | } | 577 | } |
| 693 | 578 | ||
| 694 | /** | 579 | /** |
| @@ -824,18 +709,16 @@ out: | |||
| 824 | } | 709 | } |
| 825 | 710 | ||
| 826 | /** | 711 | /** |
| 827 | * avc_ss_reset - Flush the cache and revalidate migrated permissions. | 712 | * avc_flush - Flush the cache |
| 828 | * @seqno: policy sequence number | ||
| 829 | */ | 713 | */ |
| 830 | int avc_ss_reset(u32 seqno) | 714 | static void avc_flush(void) |
| 831 | { | 715 | { |
| 832 | struct avc_callback_node *c; | ||
| 833 | int i, rc = 0, tmprc; | ||
| 834 | unsigned long flag; | ||
| 835 | struct avc_node *node; | ||
| 836 | struct hlist_head *head; | 716 | struct hlist_head *head; |
| 837 | struct hlist_node *next; | 717 | struct hlist_node *next; |
| 718 | struct avc_node *node; | ||
| 838 | spinlock_t *lock; | 719 | spinlock_t *lock; |
| 720 | unsigned long flag; | ||
| 721 | int i; | ||
| 839 | 722 | ||
| 840 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | 723 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
| 841 | head = &avc_cache.slots[i]; | 724 | head = &avc_cache.slots[i]; |
| @@ -852,6 +735,18 @@ int avc_ss_reset(u32 seqno) | |||
| 852 | rcu_read_unlock(); | 735 | rcu_read_unlock(); |
| 853 | spin_unlock_irqrestore(lock, flag); | 736 | spin_unlock_irqrestore(lock, flag); |
| 854 | } | 737 | } |
| 738 | } | ||
| 739 | |||
| 740 | /** | ||
| 741 | * avc_ss_reset - Flush the cache and revalidate migrated permissions. | ||
| 742 | * @seqno: policy sequence number | ||
| 743 | */ | ||
| 744 | int avc_ss_reset(u32 seqno) | ||
| 745 | { | ||
| 746 | struct avc_callback_node *c; | ||
| 747 | int rc = 0, tmprc; | ||
| 748 | |||
| 749 | avc_flush(); | ||
| 855 | 750 | ||
| 856 | for (c = avc_callbacks; c; c = c->next) { | 751 | for (c = avc_callbacks; c; c = c->next) { |
| 857 | if (c->events & AVC_CALLBACK_RESET) { | 752 | if (c->events & AVC_CALLBACK_RESET) { |
| @@ -956,7 +851,7 @@ out: | |||
| 956 | * another -errno upon other errors. | 851 | * another -errno upon other errors. |
| 957 | */ | 852 | */ |
| 958 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 853 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, |
| 959 | u32 requested, struct avc_audit_data *auditdata) | 854 | u32 requested, struct common_audit_data *auditdata) |
| 960 | { | 855 | { |
| 961 | struct av_decision avd; | 856 | struct av_decision avd; |
| 962 | int rc; | 857 | int rc; |
| @@ -970,3 +865,22 @@ u32 avc_policy_seqno(void) | |||
| 970 | { | 865 | { |
| 971 | return avc_cache.latest_notif; | 866 | return avc_cache.latest_notif; |
| 972 | } | 867 | } |
| 868 | |||
| 869 | void avc_disable(void) | ||
| 870 | { | ||
| 871 | /* | ||
| 872 | * If you are looking at this because you have realized that we are | ||
| 873 | * not destroying the avc_node_cachep it might be easy to fix, but | ||
| 874 | * I don't know the memory barrier semantics well enough to know. It's | ||
| 875 | * possible that some other task dereferenced security_ops when | ||
| 876 | * it still pointed to selinux operations. If that is the case it's | ||
| 877 | * possible that it is about to use the avc and is about to need the | ||
| 878 | * avc_node_cachep. I know I could wrap the security.c security_ops call | ||
| 879 | * in an rcu_lock, but seriously, it's not worth it. Instead I just flush | ||
| 880 | * the cache and get that memory back. | ||
| 881 | */ | ||
| 882 | if (avc_node_cachep) { | ||
| 883 | avc_flush(); | ||
| 884 | /* kmem_cache_destroy(avc_node_cachep); */ | ||
| 885 | } | ||
| 886 | } | ||
diff --git a/security/selinux/exports.c b/security/selinux/exports.c index c73aeaa008e8..c0a454aee1e0 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c | |||
| @@ -63,3 +63,9 @@ void selinux_secmark_refcount_dec(void) | |||
| 63 | atomic_dec(&selinux_secmark_refcount); | 63 | atomic_dec(&selinux_secmark_refcount); |
| 64 | } | 64 | } |
| 65 | EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); | 65 | EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); |
| 66 | |||
| 67 | bool selinux_is_enabled(void) | ||
| 68 | { | ||
| 69 | return selinux_enabled; | ||
| 70 | } | ||
| 71 | EXPORT_SYMBOL_GPL(selinux_is_enabled); | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 15c2a08a66f1..bb230d5d7085 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -13,8 +13,8 @@ | |||
| 13 | * Eric Paris <eparis@redhat.com> | 13 | * Eric Paris <eparis@redhat.com> |
| 14 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 14 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
| 15 | * <dgoeddel@trustedcs.com> | 15 | * <dgoeddel@trustedcs.com> |
| 16 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 16 | * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P. |
| 17 | * Paul Moore <paul.moore@hp.com> | 17 | * Paul Moore <paul.moore@hp.com> |
| 18 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. | 18 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. |
| 19 | * Yuichi Nakamura <ynakam@hitachisoft.jp> | 19 | * Yuichi Nakamura <ynakam@hitachisoft.jp> |
| 20 | * | 20 | * |
| @@ -448,6 +448,10 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 448 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | 448 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) |
| 449 | sbsec->flags &= ~SE_SBLABELSUPP; | 449 | sbsec->flags &= ~SE_SBLABELSUPP; |
| 450 | 450 | ||
| 451 | /* Special handling for sysfs. Is genfs but also has setxattr handler*/ | ||
| 452 | if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) | ||
| 453 | sbsec->flags |= SE_SBLABELSUPP; | ||
| 454 | |||
| 451 | /* Initialize the root inode. */ | 455 | /* Initialize the root inode. */ |
| 452 | rc = inode_doinit_with_dentry(root_inode, root); | 456 | rc = inode_doinit_with_dentry(root_inode, root); |
| 453 | 457 | ||
| @@ -1285,6 +1289,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
| 1285 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, | 1289 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, |
| 1286 | context, len); | 1290 | context, len); |
| 1287 | if (rc == -ERANGE) { | 1291 | if (rc == -ERANGE) { |
| 1292 | kfree(context); | ||
| 1293 | |||
| 1288 | /* Need a larger buffer. Query for the right size. */ | 1294 | /* Need a larger buffer. Query for the right size. */ |
| 1289 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, | 1295 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, |
| 1290 | NULL, 0); | 1296 | NULL, 0); |
| @@ -1292,7 +1298,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
| 1292 | dput(dentry); | 1298 | dput(dentry); |
| 1293 | goto out_unlock; | 1299 | goto out_unlock; |
| 1294 | } | 1300 | } |
| 1295 | kfree(context); | ||
| 1296 | len = rc; | 1301 | len = rc; |
| 1297 | context = kmalloc(len+1, GFP_NOFS); | 1302 | context = kmalloc(len+1, GFP_NOFS); |
| 1298 | if (!context) { | 1303 | if (!context) { |
| @@ -1478,14 +1483,14 @@ static int task_has_capability(struct task_struct *tsk, | |||
| 1478 | const struct cred *cred, | 1483 | const struct cred *cred, |
| 1479 | int cap, int audit) | 1484 | int cap, int audit) |
| 1480 | { | 1485 | { |
| 1481 | struct avc_audit_data ad; | 1486 | struct common_audit_data ad; |
| 1482 | struct av_decision avd; | 1487 | struct av_decision avd; |
| 1483 | u16 sclass; | 1488 | u16 sclass; |
| 1484 | u32 sid = cred_sid(cred); | 1489 | u32 sid = cred_sid(cred); |
| 1485 | u32 av = CAP_TO_MASK(cap); | 1490 | u32 av = CAP_TO_MASK(cap); |
| 1486 | int rc; | 1491 | int rc; |
| 1487 | 1492 | ||
| 1488 | AVC_AUDIT_DATA_INIT(&ad, CAP); | 1493 | COMMON_AUDIT_DATA_INIT(&ad, CAP); |
| 1489 | ad.tsk = tsk; | 1494 | ad.tsk = tsk; |
| 1490 | ad.u.cap = cap; | 1495 | ad.u.cap = cap; |
| 1491 | 1496 | ||
| @@ -1524,12 +1529,14 @@ static int task_has_system(struct task_struct *tsk, | |||
| 1524 | static int inode_has_perm(const struct cred *cred, | 1529 | static int inode_has_perm(const struct cred *cred, |
| 1525 | struct inode *inode, | 1530 | struct inode *inode, |
| 1526 | u32 perms, | 1531 | u32 perms, |
| 1527 | struct avc_audit_data *adp) | 1532 | struct common_audit_data *adp) |
| 1528 | { | 1533 | { |
| 1529 | struct inode_security_struct *isec; | 1534 | struct inode_security_struct *isec; |
| 1530 | struct avc_audit_data ad; | 1535 | struct common_audit_data ad; |
| 1531 | u32 sid; | 1536 | u32 sid; |
| 1532 | 1537 | ||
| 1538 | validate_creds(cred); | ||
| 1539 | |||
| 1533 | if (unlikely(IS_PRIVATE(inode))) | 1540 | if (unlikely(IS_PRIVATE(inode))) |
| 1534 | return 0; | 1541 | return 0; |
| 1535 | 1542 | ||
| @@ -1538,7 +1545,7 @@ static int inode_has_perm(const struct cred *cred, | |||
| 1538 | 1545 | ||
| 1539 | if (!adp) { | 1546 | if (!adp) { |
| 1540 | adp = &ad; | 1547 | adp = &ad; |
| 1541 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1548 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1542 | ad.u.fs.inode = inode; | 1549 | ad.u.fs.inode = inode; |
| 1543 | } | 1550 | } |
| 1544 | 1551 | ||
| @@ -1554,9 +1561,9 @@ static inline int dentry_has_perm(const struct cred *cred, | |||
| 1554 | u32 av) | 1561 | u32 av) |
| 1555 | { | 1562 | { |
| 1556 | struct inode *inode = dentry->d_inode; | 1563 | struct inode *inode = dentry->d_inode; |
| 1557 | struct avc_audit_data ad; | 1564 | struct common_audit_data ad; |
| 1558 | 1565 | ||
| 1559 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1566 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1560 | ad.u.fs.path.mnt = mnt; | 1567 | ad.u.fs.path.mnt = mnt; |
| 1561 | ad.u.fs.path.dentry = dentry; | 1568 | ad.u.fs.path.dentry = dentry; |
| 1562 | return inode_has_perm(cred, inode, av, &ad); | 1569 | return inode_has_perm(cred, inode, av, &ad); |
| @@ -1576,11 +1583,11 @@ static int file_has_perm(const struct cred *cred, | |||
| 1576 | { | 1583 | { |
| 1577 | struct file_security_struct *fsec = file->f_security; | 1584 | struct file_security_struct *fsec = file->f_security; |
| 1578 | struct inode *inode = file->f_path.dentry->d_inode; | 1585 | struct inode *inode = file->f_path.dentry->d_inode; |
| 1579 | struct avc_audit_data ad; | 1586 | struct common_audit_data ad; |
| 1580 | u32 sid = cred_sid(cred); | 1587 | u32 sid = cred_sid(cred); |
| 1581 | int rc; | 1588 | int rc; |
| 1582 | 1589 | ||
| 1583 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1590 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1584 | ad.u.fs.path = file->f_path; | 1591 | ad.u.fs.path = file->f_path; |
| 1585 | 1592 | ||
| 1586 | if (sid != fsec->sid) { | 1593 | if (sid != fsec->sid) { |
| @@ -1611,7 +1618,7 @@ static int may_create(struct inode *dir, | |||
| 1611 | struct inode_security_struct *dsec; | 1618 | struct inode_security_struct *dsec; |
| 1612 | struct superblock_security_struct *sbsec; | 1619 | struct superblock_security_struct *sbsec; |
| 1613 | u32 sid, newsid; | 1620 | u32 sid, newsid; |
| 1614 | struct avc_audit_data ad; | 1621 | struct common_audit_data ad; |
| 1615 | int rc; | 1622 | int rc; |
| 1616 | 1623 | ||
| 1617 | dsec = dir->i_security; | 1624 | dsec = dir->i_security; |
| @@ -1620,7 +1627,7 @@ static int may_create(struct inode *dir, | |||
| 1620 | sid = tsec->sid; | 1627 | sid = tsec->sid; |
| 1621 | newsid = tsec->create_sid; | 1628 | newsid = tsec->create_sid; |
| 1622 | 1629 | ||
| 1623 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1630 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1624 | ad.u.fs.path.dentry = dentry; | 1631 | ad.u.fs.path.dentry = dentry; |
| 1625 | 1632 | ||
| 1626 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1633 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
| @@ -1664,7 +1671,7 @@ static int may_link(struct inode *dir, | |||
| 1664 | 1671 | ||
| 1665 | { | 1672 | { |
| 1666 | struct inode_security_struct *dsec, *isec; | 1673 | struct inode_security_struct *dsec, *isec; |
| 1667 | struct avc_audit_data ad; | 1674 | struct common_audit_data ad; |
| 1668 | u32 sid = current_sid(); | 1675 | u32 sid = current_sid(); |
| 1669 | u32 av; | 1676 | u32 av; |
| 1670 | int rc; | 1677 | int rc; |
| @@ -1672,7 +1679,7 @@ static int may_link(struct inode *dir, | |||
| 1672 | dsec = dir->i_security; | 1679 | dsec = dir->i_security; |
| 1673 | isec = dentry->d_inode->i_security; | 1680 | isec = dentry->d_inode->i_security; |
| 1674 | 1681 | ||
| 1675 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1682 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1676 | ad.u.fs.path.dentry = dentry; | 1683 | ad.u.fs.path.dentry = dentry; |
| 1677 | 1684 | ||
| 1678 | av = DIR__SEARCH; | 1685 | av = DIR__SEARCH; |
| @@ -1707,7 +1714,7 @@ static inline int may_rename(struct inode *old_dir, | |||
| 1707 | struct dentry *new_dentry) | 1714 | struct dentry *new_dentry) |
| 1708 | { | 1715 | { |
| 1709 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; | 1716 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; |
| 1710 | struct avc_audit_data ad; | 1717 | struct common_audit_data ad; |
| 1711 | u32 sid = current_sid(); | 1718 | u32 sid = current_sid(); |
| 1712 | u32 av; | 1719 | u32 av; |
| 1713 | int old_is_dir, new_is_dir; | 1720 | int old_is_dir, new_is_dir; |
| @@ -1718,7 +1725,7 @@ static inline int may_rename(struct inode *old_dir, | |||
| 1718 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1725 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
| 1719 | new_dsec = new_dir->i_security; | 1726 | new_dsec = new_dir->i_security; |
| 1720 | 1727 | ||
| 1721 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1728 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1722 | 1729 | ||
| 1723 | ad.u.fs.path.dentry = old_dentry; | 1730 | ad.u.fs.path.dentry = old_dentry; |
| 1724 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1731 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
| @@ -1760,7 +1767,7 @@ static inline int may_rename(struct inode *old_dir, | |||
| 1760 | static int superblock_has_perm(const struct cred *cred, | 1767 | static int superblock_has_perm(const struct cred *cred, |
| 1761 | struct super_block *sb, | 1768 | struct super_block *sb, |
| 1762 | u32 perms, | 1769 | u32 perms, |
| 1763 | struct avc_audit_data *ad) | 1770 | struct common_audit_data *ad) |
| 1764 | { | 1771 | { |
| 1765 | struct superblock_security_struct *sbsec; | 1772 | struct superblock_security_struct *sbsec; |
| 1766 | u32 sid = cred_sid(cred); | 1773 | u32 sid = cred_sid(cred); |
| @@ -1854,12 +1861,12 @@ static inline u32 open_file_to_av(struct file *file) | |||
| 1854 | 1861 | ||
| 1855 | /* Hook functions begin here. */ | 1862 | /* Hook functions begin here. */ |
| 1856 | 1863 | ||
| 1857 | static int selinux_ptrace_may_access(struct task_struct *child, | 1864 | static int selinux_ptrace_access_check(struct task_struct *child, |
| 1858 | unsigned int mode) | 1865 | unsigned int mode) |
| 1859 | { | 1866 | { |
| 1860 | int rc; | 1867 | int rc; |
| 1861 | 1868 | ||
| 1862 | rc = cap_ptrace_may_access(child, mode); | 1869 | rc = cap_ptrace_access_check(child, mode); |
| 1863 | if (rc) | 1870 | if (rc) |
| 1864 | return rc; | 1871 | return rc; |
| 1865 | 1872 | ||
| @@ -2100,7 +2107,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2100 | const struct task_security_struct *old_tsec; | 2107 | const struct task_security_struct *old_tsec; |
| 2101 | struct task_security_struct *new_tsec; | 2108 | struct task_security_struct *new_tsec; |
| 2102 | struct inode_security_struct *isec; | 2109 | struct inode_security_struct *isec; |
| 2103 | struct avc_audit_data ad; | 2110 | struct common_audit_data ad; |
| 2104 | struct inode *inode = bprm->file->f_path.dentry->d_inode; | 2111 | struct inode *inode = bprm->file->f_path.dentry->d_inode; |
| 2105 | int rc; | 2112 | int rc; |
| 2106 | 2113 | ||
| @@ -2138,7 +2145,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2138 | return rc; | 2145 | return rc; |
| 2139 | } | 2146 | } |
| 2140 | 2147 | ||
| 2141 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2148 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2142 | ad.u.fs.path = bprm->file->f_path; | 2149 | ad.u.fs.path = bprm->file->f_path; |
| 2143 | 2150 | ||
| 2144 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2151 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
| @@ -2231,7 +2238,7 @@ extern struct dentry *selinux_null; | |||
| 2231 | static inline void flush_unauthorized_files(const struct cred *cred, | 2238 | static inline void flush_unauthorized_files(const struct cred *cred, |
| 2232 | struct files_struct *files) | 2239 | struct files_struct *files) |
| 2233 | { | 2240 | { |
| 2234 | struct avc_audit_data ad; | 2241 | struct common_audit_data ad; |
| 2235 | struct file *file, *devnull = NULL; | 2242 | struct file *file, *devnull = NULL; |
| 2236 | struct tty_struct *tty; | 2243 | struct tty_struct *tty; |
| 2237 | struct fdtable *fdt; | 2244 | struct fdtable *fdt; |
| @@ -2265,7 +2272,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
| 2265 | 2272 | ||
| 2266 | /* Revalidate access to inherited open files. */ | 2273 | /* Revalidate access to inherited open files. */ |
| 2267 | 2274 | ||
| 2268 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2275 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2269 | 2276 | ||
| 2270 | spin_lock(&files->file_lock); | 2277 | spin_lock(&files->file_lock); |
| 2271 | for (;;) { | 2278 | for (;;) { |
| @@ -2404,7 +2411,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) | |||
| 2404 | /* Wake up the parent if it is waiting so that it can recheck | 2411 | /* Wake up the parent if it is waiting so that it can recheck |
| 2405 | * wait permission to the new task SID. */ | 2412 | * wait permission to the new task SID. */ |
| 2406 | read_lock(&tasklist_lock); | 2413 | read_lock(&tasklist_lock); |
| 2407 | wake_up_interruptible(¤t->real_parent->signal->wait_chldexit); | 2414 | __wake_up_parent(current, current->real_parent); |
| 2408 | read_unlock(&tasklist_lock); | 2415 | read_unlock(&tasklist_lock); |
| 2409 | } | 2416 | } |
| 2410 | 2417 | ||
| @@ -2514,7 +2521,7 @@ out: | |||
| 2514 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | 2521 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) |
| 2515 | { | 2522 | { |
| 2516 | const struct cred *cred = current_cred(); | 2523 | const struct cred *cred = current_cred(); |
| 2517 | struct avc_audit_data ad; | 2524 | struct common_audit_data ad; |
| 2518 | int rc; | 2525 | int rc; |
| 2519 | 2526 | ||
| 2520 | rc = superblock_doinit(sb, data); | 2527 | rc = superblock_doinit(sb, data); |
| @@ -2525,7 +2532,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 2525 | if (flags & MS_KERNMOUNT) | 2532 | if (flags & MS_KERNMOUNT) |
| 2526 | return 0; | 2533 | return 0; |
| 2527 | 2534 | ||
| 2528 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2535 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2529 | ad.u.fs.path.dentry = sb->s_root; | 2536 | ad.u.fs.path.dentry = sb->s_root; |
| 2530 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2537 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
| 2531 | } | 2538 | } |
| @@ -2533,9 +2540,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 2533 | static int selinux_sb_statfs(struct dentry *dentry) | 2540 | static int selinux_sb_statfs(struct dentry *dentry) |
| 2534 | { | 2541 | { |
| 2535 | const struct cred *cred = current_cred(); | 2542 | const struct cred *cred = current_cred(); |
| 2536 | struct avc_audit_data ad; | 2543 | struct common_audit_data ad; |
| 2537 | 2544 | ||
| 2538 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2545 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2539 | ad.u.fs.path.dentry = dentry->d_sb->s_root; | 2546 | ad.u.fs.path.dentry = dentry->d_sb->s_root; |
| 2540 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2547 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
| 2541 | } | 2548 | } |
| @@ -2710,12 +2717,18 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
| 2710 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2717 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
| 2711 | { | 2718 | { |
| 2712 | const struct cred *cred = current_cred(); | 2719 | const struct cred *cred = current_cred(); |
| 2720 | unsigned int ia_valid = iattr->ia_valid; | ||
| 2721 | |||
| 2722 | /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ | ||
| 2723 | if (ia_valid & ATTR_FORCE) { | ||
| 2724 | ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE | | ||
| 2725 | ATTR_FORCE); | ||
| 2726 | if (!ia_valid) | ||
| 2727 | return 0; | ||
| 2728 | } | ||
| 2713 | 2729 | ||
| 2714 | if (iattr->ia_valid & ATTR_FORCE) | 2730 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | |
| 2715 | return 0; | 2731 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
| 2716 | |||
| 2717 | if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | | ||
| 2718 | ATTR_ATIME_SET | ATTR_MTIME_SET)) | ||
| 2719 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | 2732 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); |
| 2720 | 2733 | ||
| 2721 | return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); | 2734 | return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); |
| @@ -2755,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 2755 | struct inode *inode = dentry->d_inode; | 2768 | struct inode *inode = dentry->d_inode; |
| 2756 | struct inode_security_struct *isec = inode->i_security; | 2769 | struct inode_security_struct *isec = inode->i_security; |
| 2757 | struct superblock_security_struct *sbsec; | 2770 | struct superblock_security_struct *sbsec; |
| 2758 | struct avc_audit_data ad; | 2771 | struct common_audit_data ad; |
| 2759 | u32 newsid, sid = current_sid(); | 2772 | u32 newsid, sid = current_sid(); |
| 2760 | int rc = 0; | 2773 | int rc = 0; |
| 2761 | 2774 | ||
| @@ -2769,7 +2782,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 2769 | if (!is_owner_or_cap(inode)) | 2782 | if (!is_owner_or_cap(inode)) |
| 2770 | return -EPERM; | 2783 | return -EPERM; |
| 2771 | 2784 | ||
| 2772 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2785 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2773 | ad.u.fs.path.dentry = dentry; | 2786 | ad.u.fs.path.dentry = dentry; |
| 2774 | 2787 | ||
| 2775 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2788 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
| @@ -2914,6 +2927,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, | |||
| 2914 | return rc; | 2927 | return rc; |
| 2915 | 2928 | ||
| 2916 | isec->sid = newsid; | 2929 | isec->sid = newsid; |
| 2930 | isec->initialized = 1; | ||
| 2917 | return 0; | 2931 | return 0; |
| 2918 | } | 2932 | } |
| 2919 | 2933 | ||
| @@ -2938,11 +2952,6 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
| 2938 | const struct cred *cred = current_cred(); | 2952 | const struct cred *cred = current_cred(); |
| 2939 | struct inode *inode = file->f_path.dentry->d_inode; | 2953 | struct inode *inode = file->f_path.dentry->d_inode; |
| 2940 | 2954 | ||
| 2941 | if (!mask) { | ||
| 2942 | /* No permission to check. Existence test. */ | ||
| 2943 | return 0; | ||
| 2944 | } | ||
| 2945 | |||
| 2946 | /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ | 2955 | /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ |
| 2947 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) | 2956 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) |
| 2948 | mask |= MAY_APPEND; | 2957 | mask |= MAY_APPEND; |
| @@ -2953,10 +2962,20 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
| 2953 | 2962 | ||
| 2954 | static int selinux_file_permission(struct file *file, int mask) | 2963 | static int selinux_file_permission(struct file *file, int mask) |
| 2955 | { | 2964 | { |
| 2965 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 2966 | struct file_security_struct *fsec = file->f_security; | ||
| 2967 | struct inode_security_struct *isec = inode->i_security; | ||
| 2968 | u32 sid = current_sid(); | ||
| 2969 | |||
| 2956 | if (!mask) | 2970 | if (!mask) |
| 2957 | /* No permission to check. Existence test. */ | 2971 | /* No permission to check. Existence test. */ |
| 2958 | return 0; | 2972 | return 0; |
| 2959 | 2973 | ||
| 2974 | if (sid == fsec->sid && fsec->isid == isec->sid && | ||
| 2975 | fsec->pseqno == avc_policy_seqno()) | ||
| 2976 | /* No change since dentry_open check. */ | ||
| 2977 | return 0; | ||
| 2978 | |||
| 2960 | return selinux_revalidate_file_permission(file, mask); | 2979 | return selinux_revalidate_file_permission(file, mask); |
| 2961 | } | 2980 | } |
| 2962 | 2981 | ||
| @@ -3029,9 +3048,21 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, | |||
| 3029 | int rc = 0; | 3048 | int rc = 0; |
| 3030 | u32 sid = current_sid(); | 3049 | u32 sid = current_sid(); |
| 3031 | 3050 | ||
| 3032 | if (addr < mmap_min_addr) | 3051 | /* |
| 3052 | * notice that we are intentionally putting the SELinux check before | ||
| 3053 | * the secondary cap_file_mmap check. This is such a likely attempt | ||
| 3054 | * at bad behaviour/exploit that we always want to get the AVC, even | ||
| 3055 | * if DAC would have also denied the operation. | ||
| 3056 | */ | ||
| 3057 | if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { | ||
| 3033 | rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, | 3058 | rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, |
| 3034 | MEMPROTECT__MMAP_ZERO, NULL); | 3059 | MEMPROTECT__MMAP_ZERO, NULL); |
| 3060 | if (rc) | ||
| 3061 | return rc; | ||
| 3062 | } | ||
| 3063 | |||
| 3064 | /* do DAC check on address space usage */ | ||
| 3065 | rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); | ||
| 3035 | if (rc || addr_only) | 3066 | if (rc || addr_only) |
| 3036 | return rc; | 3067 | return rc; |
| 3037 | 3068 | ||
| @@ -3207,12 +3238,29 @@ static int selinux_task_create(unsigned long clone_flags) | |||
| 3207 | } | 3238 | } |
| 3208 | 3239 | ||
| 3209 | /* | 3240 | /* |
| 3241 | * allocate the SELinux part of blank credentials | ||
| 3242 | */ | ||
| 3243 | static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 3244 | { | ||
| 3245 | struct task_security_struct *tsec; | ||
| 3246 | |||
| 3247 | tsec = kzalloc(sizeof(struct task_security_struct), gfp); | ||
| 3248 | if (!tsec) | ||
| 3249 | return -ENOMEM; | ||
| 3250 | |||
| 3251 | cred->security = tsec; | ||
| 3252 | return 0; | ||
| 3253 | } | ||
| 3254 | |||
| 3255 | /* | ||
| 3210 | * detach and free the LSM part of a set of credentials | 3256 | * detach and free the LSM part of a set of credentials |
| 3211 | */ | 3257 | */ |
| 3212 | static void selinux_cred_free(struct cred *cred) | 3258 | static void selinux_cred_free(struct cred *cred) |
| 3213 | { | 3259 | { |
| 3214 | struct task_security_struct *tsec = cred->security; | 3260 | struct task_security_struct *tsec = cred->security; |
| 3215 | cred->security = NULL; | 3261 | |
| 3262 | BUG_ON((unsigned long) cred->security < PAGE_SIZE); | ||
| 3263 | cred->security = (void *) 0x7UL; | ||
| 3216 | kfree(tsec); | 3264 | kfree(tsec); |
| 3217 | } | 3265 | } |
| 3218 | 3266 | ||
| @@ -3236,6 +3284,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, | |||
| 3236 | } | 3284 | } |
| 3237 | 3285 | ||
| 3238 | /* | 3286 | /* |
| 3287 | * transfer the SELinux data to a blank set of creds | ||
| 3288 | */ | ||
| 3289 | static void selinux_cred_transfer(struct cred *new, const struct cred *old) | ||
| 3290 | { | ||
| 3291 | const struct task_security_struct *old_tsec = old->security; | ||
| 3292 | struct task_security_struct *tsec = new->security; | ||
| 3293 | |||
| 3294 | *tsec = *old_tsec; | ||
| 3295 | } | ||
| 3296 | |||
| 3297 | /* | ||
| 3239 | * set the security data for a kernel service | 3298 | * set the security data for a kernel service |
| 3240 | * - all the creation contexts are set to unlabelled | 3299 | * - all the creation contexts are set to unlabelled |
| 3241 | */ | 3300 | */ |
| @@ -3279,6 +3338,11 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 3279 | return 0; | 3338 | return 0; |
| 3280 | } | 3339 | } |
| 3281 | 3340 | ||
| 3341 | static int selinux_kernel_module_request(void) | ||
| 3342 | { | ||
| 3343 | return task_has_system(current, SYSTEM__MODULE_REQUEST); | ||
| 3344 | } | ||
| 3345 | |||
| 3282 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) | 3346 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) |
| 3283 | { | 3347 | { |
| 3284 | return current_has_perm(p, PROCESS__SETPGID); | 3348 | return current_has_perm(p, PROCESS__SETPGID); |
| @@ -3396,7 +3460,7 @@ static void selinux_task_to_inode(struct task_struct *p, | |||
| 3396 | 3460 | ||
| 3397 | /* Returns error only if unable to parse addresses */ | 3461 | /* Returns error only if unable to parse addresses */ |
| 3398 | static int selinux_parse_skb_ipv4(struct sk_buff *skb, | 3462 | static int selinux_parse_skb_ipv4(struct sk_buff *skb, |
| 3399 | struct avc_audit_data *ad, u8 *proto) | 3463 | struct common_audit_data *ad, u8 *proto) |
| 3400 | { | 3464 | { |
| 3401 | int offset, ihlen, ret = -EINVAL; | 3465 | int offset, ihlen, ret = -EINVAL; |
| 3402 | struct iphdr _iph, *ih; | 3466 | struct iphdr _iph, *ih; |
| @@ -3477,7 +3541,7 @@ out: | |||
| 3477 | 3541 | ||
| 3478 | /* Returns error only if unable to parse addresses */ | 3542 | /* Returns error only if unable to parse addresses */ |
| 3479 | static int selinux_parse_skb_ipv6(struct sk_buff *skb, | 3543 | static int selinux_parse_skb_ipv6(struct sk_buff *skb, |
| 3480 | struct avc_audit_data *ad, u8 *proto) | 3544 | struct common_audit_data *ad, u8 *proto) |
| 3481 | { | 3545 | { |
| 3482 | u8 nexthdr; | 3546 | u8 nexthdr; |
| 3483 | int ret = -EINVAL, offset; | 3547 | int ret = -EINVAL, offset; |
| @@ -3548,7 +3612,7 @@ out: | |||
| 3548 | 3612 | ||
| 3549 | #endif /* IPV6 */ | 3613 | #endif /* IPV6 */ |
| 3550 | 3614 | ||
| 3551 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | 3615 | static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, |
| 3552 | char **_addrp, int src, u8 *proto) | 3616 | char **_addrp, int src, u8 *proto) |
| 3553 | { | 3617 | { |
| 3554 | char *addrp; | 3618 | char *addrp; |
| @@ -3630,7 +3694,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, | |||
| 3630 | u32 perms) | 3694 | u32 perms) |
| 3631 | { | 3695 | { |
| 3632 | struct inode_security_struct *isec; | 3696 | struct inode_security_struct *isec; |
| 3633 | struct avc_audit_data ad; | 3697 | struct common_audit_data ad; |
| 3634 | u32 sid; | 3698 | u32 sid; |
| 3635 | int err = 0; | 3699 | int err = 0; |
| 3636 | 3700 | ||
| @@ -3640,7 +3704,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, | |||
| 3640 | goto out; | 3704 | goto out; |
| 3641 | sid = task_sid(task); | 3705 | sid = task_sid(task); |
| 3642 | 3706 | ||
| 3643 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3707 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3644 | ad.u.net.sk = sock->sk; | 3708 | ad.u.net.sk = sock->sk; |
| 3645 | err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | 3709 | err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); |
| 3646 | 3710 | ||
| @@ -3727,7 +3791,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3727 | if (family == PF_INET || family == PF_INET6) { | 3791 | if (family == PF_INET || family == PF_INET6) { |
| 3728 | char *addrp; | 3792 | char *addrp; |
| 3729 | struct inode_security_struct *isec; | 3793 | struct inode_security_struct *isec; |
| 3730 | struct avc_audit_data ad; | 3794 | struct common_audit_data ad; |
| 3731 | struct sockaddr_in *addr4 = NULL; | 3795 | struct sockaddr_in *addr4 = NULL; |
| 3732 | struct sockaddr_in6 *addr6 = NULL; | 3796 | struct sockaddr_in6 *addr6 = NULL; |
| 3733 | unsigned short snum; | 3797 | unsigned short snum; |
| @@ -3756,7 +3820,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3756 | snum, &sid); | 3820 | snum, &sid); |
| 3757 | if (err) | 3821 | if (err) |
| 3758 | goto out; | 3822 | goto out; |
| 3759 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3823 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3760 | ad.u.net.sport = htons(snum); | 3824 | ad.u.net.sport = htons(snum); |
| 3761 | ad.u.net.family = family; | 3825 | ad.u.net.family = family; |
| 3762 | err = avc_has_perm(isec->sid, sid, | 3826 | err = avc_has_perm(isec->sid, sid, |
| @@ -3789,7 +3853,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3789 | if (err) | 3853 | if (err) |
| 3790 | goto out; | 3854 | goto out; |
| 3791 | 3855 | ||
| 3792 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3856 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3793 | ad.u.net.sport = htons(snum); | 3857 | ad.u.net.sport = htons(snum); |
| 3794 | ad.u.net.family = family; | 3858 | ad.u.net.family = family; |
| 3795 | 3859 | ||
| @@ -3823,7 +3887,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3823 | isec = SOCK_INODE(sock)->i_security; | 3887 | isec = SOCK_INODE(sock)->i_security; |
| 3824 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3888 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
| 3825 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3889 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
| 3826 | struct avc_audit_data ad; | 3890 | struct common_audit_data ad; |
| 3827 | struct sockaddr_in *addr4 = NULL; | 3891 | struct sockaddr_in *addr4 = NULL; |
| 3828 | struct sockaddr_in6 *addr6 = NULL; | 3892 | struct sockaddr_in6 *addr6 = NULL; |
| 3829 | unsigned short snum; | 3893 | unsigned short snum; |
| @@ -3848,7 +3912,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3848 | perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? | 3912 | perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? |
| 3849 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | 3913 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; |
| 3850 | 3914 | ||
| 3851 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3915 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3852 | ad.u.net.dport = htons(snum); | 3916 | ad.u.net.dport = htons(snum); |
| 3853 | ad.u.net.family = sk->sk_family; | 3917 | ad.u.net.family = sk->sk_family; |
| 3854 | err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); | 3918 | err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); |
| @@ -3938,13 +4002,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
| 3938 | struct sk_security_struct *ssec; | 4002 | struct sk_security_struct *ssec; |
| 3939 | struct inode_security_struct *isec; | 4003 | struct inode_security_struct *isec; |
| 3940 | struct inode_security_struct *other_isec; | 4004 | struct inode_security_struct *other_isec; |
| 3941 | struct avc_audit_data ad; | 4005 | struct common_audit_data ad; |
| 3942 | int err; | 4006 | int err; |
| 3943 | 4007 | ||
| 3944 | isec = SOCK_INODE(sock)->i_security; | 4008 | isec = SOCK_INODE(sock)->i_security; |
| 3945 | other_isec = SOCK_INODE(other)->i_security; | 4009 | other_isec = SOCK_INODE(other)->i_security; |
| 3946 | 4010 | ||
| 3947 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4011 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3948 | ad.u.net.sk = other->sk; | 4012 | ad.u.net.sk = other->sk; |
| 3949 | 4013 | ||
| 3950 | err = avc_has_perm(isec->sid, other_isec->sid, | 4014 | err = avc_has_perm(isec->sid, other_isec->sid, |
| @@ -3970,13 +4034,13 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 3970 | { | 4034 | { |
| 3971 | struct inode_security_struct *isec; | 4035 | struct inode_security_struct *isec; |
| 3972 | struct inode_security_struct *other_isec; | 4036 | struct inode_security_struct *other_isec; |
| 3973 | struct avc_audit_data ad; | 4037 | struct common_audit_data ad; |
| 3974 | int err; | 4038 | int err; |
| 3975 | 4039 | ||
| 3976 | isec = SOCK_INODE(sock)->i_security; | 4040 | isec = SOCK_INODE(sock)->i_security; |
| 3977 | other_isec = SOCK_INODE(other)->i_security; | 4041 | other_isec = SOCK_INODE(other)->i_security; |
| 3978 | 4042 | ||
| 3979 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4043 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3980 | ad.u.net.sk = other->sk; | 4044 | ad.u.net.sk = other->sk; |
| 3981 | 4045 | ||
| 3982 | err = avc_has_perm(isec->sid, other_isec->sid, | 4046 | err = avc_has_perm(isec->sid, other_isec->sid, |
| @@ -3989,7 +4053,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 3989 | 4053 | ||
| 3990 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | 4054 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, |
| 3991 | u32 peer_sid, | 4055 | u32 peer_sid, |
| 3992 | struct avc_audit_data *ad) | 4056 | struct common_audit_data *ad) |
| 3993 | { | 4057 | { |
| 3994 | int err; | 4058 | int err; |
| 3995 | u32 if_sid; | 4059 | u32 if_sid; |
| @@ -4017,10 +4081,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
| 4017 | struct sk_security_struct *sksec = sk->sk_security; | 4081 | struct sk_security_struct *sksec = sk->sk_security; |
| 4018 | u32 peer_sid; | 4082 | u32 peer_sid; |
| 4019 | u32 sk_sid = sksec->sid; | 4083 | u32 sk_sid = sksec->sid; |
| 4020 | struct avc_audit_data ad; | 4084 | struct common_audit_data ad; |
| 4021 | char *addrp; | 4085 | char *addrp; |
| 4022 | 4086 | ||
| 4023 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4087 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4024 | ad.u.net.netif = skb->iif; | 4088 | ad.u.net.netif = skb->iif; |
| 4025 | ad.u.net.family = family; | 4089 | ad.u.net.family = family; |
| 4026 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | 4090 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); |
| @@ -4058,7 +4122,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4058 | struct sk_security_struct *sksec = sk->sk_security; | 4122 | struct sk_security_struct *sksec = sk->sk_security; |
| 4059 | u16 family = sk->sk_family; | 4123 | u16 family = sk->sk_family; |
| 4060 | u32 sk_sid = sksec->sid; | 4124 | u32 sk_sid = sksec->sid; |
| 4061 | struct avc_audit_data ad; | 4125 | struct common_audit_data ad; |
| 4062 | char *addrp; | 4126 | char *addrp; |
| 4063 | u8 secmark_active; | 4127 | u8 secmark_active; |
| 4064 | u8 peerlbl_active; | 4128 | u8 peerlbl_active; |
| @@ -4082,7 +4146,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4082 | if (!secmark_active && !peerlbl_active) | 4146 | if (!secmark_active && !peerlbl_active) |
| 4083 | return 0; | 4147 | return 0; |
| 4084 | 4148 | ||
| 4085 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4149 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4086 | ad.u.net.netif = skb->iif; | 4150 | ad.u.net.netif = skb->iif; |
| 4087 | ad.u.net.family = family; | 4151 | ad.u.net.family = family; |
| 4088 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | 4152 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); |
| @@ -4296,6 +4360,59 @@ static void selinux_req_classify_flow(const struct request_sock *req, | |||
| 4296 | fl->secid = req->secid; | 4360 | fl->secid = req->secid; |
| 4297 | } | 4361 | } |
| 4298 | 4362 | ||
| 4363 | static int selinux_tun_dev_create(void) | ||
| 4364 | { | ||
| 4365 | u32 sid = current_sid(); | ||
| 4366 | |||
| 4367 | /* we aren't taking into account the "sockcreate" SID since the socket | ||
| 4368 | * that is being created here is not a socket in the traditional sense, | ||
| 4369 | * instead it is a private sock, accessible only to the kernel, and | ||
| 4370 | * representing a wide range of network traffic spanning multiple | ||
| 4371 | * connections unlike traditional sockets - check the TUN driver to | ||
| 4372 | * get a better understanding of why this socket is special */ | ||
| 4373 | |||
| 4374 | return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, | ||
| 4375 | NULL); | ||
| 4376 | } | ||
| 4377 | |||
| 4378 | static void selinux_tun_dev_post_create(struct sock *sk) | ||
| 4379 | { | ||
| 4380 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4381 | |||
| 4382 | /* we don't currently perform any NetLabel based labeling here and it | ||
| 4383 | * isn't clear that we would want to do so anyway; while we could apply | ||
| 4384 | * labeling without the support of the TUN user the resulting labeled | ||
| 4385 | * traffic from the other end of the connection would almost certainly | ||
| 4386 | * cause confusion to the TUN user that had no idea network labeling | ||
| 4387 | * protocols were being used */ | ||
| 4388 | |||
| 4389 | /* see the comments in selinux_tun_dev_create() about why we don't use | ||
| 4390 | * the sockcreate SID here */ | ||
| 4391 | |||
| 4392 | sksec->sid = current_sid(); | ||
| 4393 | sksec->sclass = SECCLASS_TUN_SOCKET; | ||
| 4394 | } | ||
| 4395 | |||
| 4396 | static int selinux_tun_dev_attach(struct sock *sk) | ||
| 4397 | { | ||
| 4398 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4399 | u32 sid = current_sid(); | ||
| 4400 | int err; | ||
| 4401 | |||
| 4402 | err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET, | ||
| 4403 | TUN_SOCKET__RELABELFROM, NULL); | ||
| 4404 | if (err) | ||
| 4405 | return err; | ||
| 4406 | err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, | ||
| 4407 | TUN_SOCKET__RELABELTO, NULL); | ||
| 4408 | if (err) | ||
| 4409 | return err; | ||
| 4410 | |||
| 4411 | sksec->sid = sid; | ||
| 4412 | |||
| 4413 | return 0; | ||
| 4414 | } | ||
| 4415 | |||
| 4299 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | 4416 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) |
| 4300 | { | 4417 | { |
| 4301 | int err = 0; | 4418 | int err = 0; |
| @@ -4340,7 +4457,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
| 4340 | int err; | 4457 | int err; |
| 4341 | char *addrp; | 4458 | char *addrp; |
| 4342 | u32 peer_sid; | 4459 | u32 peer_sid; |
| 4343 | struct avc_audit_data ad; | 4460 | struct common_audit_data ad; |
| 4344 | u8 secmark_active; | 4461 | u8 secmark_active; |
| 4345 | u8 netlbl_active; | 4462 | u8 netlbl_active; |
| 4346 | u8 peerlbl_active; | 4463 | u8 peerlbl_active; |
| @@ -4357,7 +4474,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
| 4357 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4474 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) |
| 4358 | return NF_DROP; | 4475 | return NF_DROP; |
| 4359 | 4476 | ||
| 4360 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4477 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4361 | ad.u.net.netif = ifindex; | 4478 | ad.u.net.netif = ifindex; |
| 4362 | ad.u.net.family = family; | 4479 | ad.u.net.family = family; |
| 4363 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4480 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
| @@ -4445,7 +4562,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
| 4445 | { | 4562 | { |
| 4446 | struct sock *sk = skb->sk; | 4563 | struct sock *sk = skb->sk; |
| 4447 | struct sk_security_struct *sksec; | 4564 | struct sk_security_struct *sksec; |
| 4448 | struct avc_audit_data ad; | 4565 | struct common_audit_data ad; |
| 4449 | char *addrp; | 4566 | char *addrp; |
| 4450 | u8 proto; | 4567 | u8 proto; |
| 4451 | 4568 | ||
| @@ -4453,7 +4570,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
| 4453 | return NF_ACCEPT; | 4570 | return NF_ACCEPT; |
| 4454 | sksec = sk->sk_security; | 4571 | sksec = sk->sk_security; |
| 4455 | 4572 | ||
| 4456 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4573 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4457 | ad.u.net.netif = ifindex; | 4574 | ad.u.net.netif = ifindex; |
| 4458 | ad.u.net.family = family; | 4575 | ad.u.net.family = family; |
| 4459 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | 4576 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) |
| @@ -4477,7 +4594,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4477 | u32 secmark_perm; | 4594 | u32 secmark_perm; |
| 4478 | u32 peer_sid; | 4595 | u32 peer_sid; |
| 4479 | struct sock *sk; | 4596 | struct sock *sk; |
| 4480 | struct avc_audit_data ad; | 4597 | struct common_audit_data ad; |
| 4481 | char *addrp; | 4598 | char *addrp; |
| 4482 | u8 secmark_active; | 4599 | u8 secmark_active; |
| 4483 | u8 peerlbl_active; | 4600 | u8 peerlbl_active; |
| @@ -4536,7 +4653,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4536 | secmark_perm = PACKET__SEND; | 4653 | secmark_perm = PACKET__SEND; |
| 4537 | } | 4654 | } |
| 4538 | 4655 | ||
| 4539 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4656 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4540 | ad.u.net.netif = ifindex; | 4657 | ad.u.net.netif = ifindex; |
| 4541 | ad.u.net.family = family; | 4658 | ad.u.net.family = family; |
| 4542 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) | 4659 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) |
| @@ -4606,13 +4723,13 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) | |||
| 4606 | static int selinux_netlink_recv(struct sk_buff *skb, int capability) | 4723 | static int selinux_netlink_recv(struct sk_buff *skb, int capability) |
| 4607 | { | 4724 | { |
| 4608 | int err; | 4725 | int err; |
| 4609 | struct avc_audit_data ad; | 4726 | struct common_audit_data ad; |
| 4610 | 4727 | ||
| 4611 | err = cap_netlink_recv(skb, capability); | 4728 | err = cap_netlink_recv(skb, capability); |
| 4612 | if (err) | 4729 | if (err) |
| 4613 | return err; | 4730 | return err; |
| 4614 | 4731 | ||
| 4615 | AVC_AUDIT_DATA_INIT(&ad, CAP); | 4732 | COMMON_AUDIT_DATA_INIT(&ad, CAP); |
| 4616 | ad.u.cap = capability; | 4733 | ad.u.cap = capability; |
| 4617 | 4734 | ||
| 4618 | return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, | 4735 | return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, |
| @@ -4671,12 +4788,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, | |||
| 4671 | u32 perms) | 4788 | u32 perms) |
| 4672 | { | 4789 | { |
| 4673 | struct ipc_security_struct *isec; | 4790 | struct ipc_security_struct *isec; |
| 4674 | struct avc_audit_data ad; | 4791 | struct common_audit_data ad; |
| 4675 | u32 sid = current_sid(); | 4792 | u32 sid = current_sid(); |
| 4676 | 4793 | ||
| 4677 | isec = ipc_perms->security; | 4794 | isec = ipc_perms->security; |
| 4678 | 4795 | ||
| 4679 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4796 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4680 | ad.u.ipc_id = ipc_perms->key; | 4797 | ad.u.ipc_id = ipc_perms->key; |
| 4681 | 4798 | ||
| 4682 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | 4799 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); |
| @@ -4696,7 +4813,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg) | |||
| 4696 | static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | 4813 | static int selinux_msg_queue_alloc_security(struct msg_queue *msq) |
| 4697 | { | 4814 | { |
| 4698 | struct ipc_security_struct *isec; | 4815 | struct ipc_security_struct *isec; |
| 4699 | struct avc_audit_data ad; | 4816 | struct common_audit_data ad; |
| 4700 | u32 sid = current_sid(); | 4817 | u32 sid = current_sid(); |
| 4701 | int rc; | 4818 | int rc; |
| 4702 | 4819 | ||
| @@ -4706,7 +4823,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | |||
| 4706 | 4823 | ||
| 4707 | isec = msq->q_perm.security; | 4824 | isec = msq->q_perm.security; |
| 4708 | 4825 | ||
| 4709 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4826 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4710 | ad.u.ipc_id = msq->q_perm.key; | 4827 | ad.u.ipc_id = msq->q_perm.key; |
| 4711 | 4828 | ||
| 4712 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4829 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
| @@ -4726,12 +4843,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq) | |||
| 4726 | static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) | 4843 | static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) |
| 4727 | { | 4844 | { |
| 4728 | struct ipc_security_struct *isec; | 4845 | struct ipc_security_struct *isec; |
| 4729 | struct avc_audit_data ad; | 4846 | struct common_audit_data ad; |
| 4730 | u32 sid = current_sid(); | 4847 | u32 sid = current_sid(); |
| 4731 | 4848 | ||
| 4732 | isec = msq->q_perm.security; | 4849 | isec = msq->q_perm.security; |
| 4733 | 4850 | ||
| 4734 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4851 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4735 | ad.u.ipc_id = msq->q_perm.key; | 4852 | ad.u.ipc_id = msq->q_perm.key; |
| 4736 | 4853 | ||
| 4737 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4854 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
| @@ -4770,7 +4887,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
| 4770 | { | 4887 | { |
| 4771 | struct ipc_security_struct *isec; | 4888 | struct ipc_security_struct *isec; |
| 4772 | struct msg_security_struct *msec; | 4889 | struct msg_security_struct *msec; |
| 4773 | struct avc_audit_data ad; | 4890 | struct common_audit_data ad; |
| 4774 | u32 sid = current_sid(); | 4891 | u32 sid = current_sid(); |
| 4775 | int rc; | 4892 | int rc; |
| 4776 | 4893 | ||
| @@ -4791,7 +4908,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
| 4791 | return rc; | 4908 | return rc; |
| 4792 | } | 4909 | } |
| 4793 | 4910 | ||
| 4794 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4911 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4795 | ad.u.ipc_id = msq->q_perm.key; | 4912 | ad.u.ipc_id = msq->q_perm.key; |
| 4796 | 4913 | ||
| 4797 | /* Can this process write to the queue? */ | 4914 | /* Can this process write to the queue? */ |
| @@ -4815,14 +4932,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, | |||
| 4815 | { | 4932 | { |
| 4816 | struct ipc_security_struct *isec; | 4933 | struct ipc_security_struct *isec; |
| 4817 | struct msg_security_struct *msec; | 4934 | struct msg_security_struct *msec; |
| 4818 | struct avc_audit_data ad; | 4935 | struct common_audit_data ad; |
| 4819 | u32 sid = task_sid(target); | 4936 | u32 sid = task_sid(target); |
| 4820 | int rc; | 4937 | int rc; |
| 4821 | 4938 | ||
| 4822 | isec = msq->q_perm.security; | 4939 | isec = msq->q_perm.security; |
| 4823 | msec = msg->security; | 4940 | msec = msg->security; |
| 4824 | 4941 | ||
| 4825 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4942 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4826 | ad.u.ipc_id = msq->q_perm.key; | 4943 | ad.u.ipc_id = msq->q_perm.key; |
| 4827 | 4944 | ||
| 4828 | rc = avc_has_perm(sid, isec->sid, | 4945 | rc = avc_has_perm(sid, isec->sid, |
| @@ -4837,7 +4954,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, | |||
| 4837 | static int selinux_shm_alloc_security(struct shmid_kernel *shp) | 4954 | static int selinux_shm_alloc_security(struct shmid_kernel *shp) |
| 4838 | { | 4955 | { |
| 4839 | struct ipc_security_struct *isec; | 4956 | struct ipc_security_struct *isec; |
| 4840 | struct avc_audit_data ad; | 4957 | struct common_audit_data ad; |
| 4841 | u32 sid = current_sid(); | 4958 | u32 sid = current_sid(); |
| 4842 | int rc; | 4959 | int rc; |
| 4843 | 4960 | ||
| @@ -4847,7 +4964,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) | |||
| 4847 | 4964 | ||
| 4848 | isec = shp->shm_perm.security; | 4965 | isec = shp->shm_perm.security; |
| 4849 | 4966 | ||
| 4850 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4967 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4851 | ad.u.ipc_id = shp->shm_perm.key; | 4968 | ad.u.ipc_id = shp->shm_perm.key; |
| 4852 | 4969 | ||
| 4853 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 4970 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
| @@ -4867,12 +4984,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp) | |||
| 4867 | static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) | 4984 | static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) |
| 4868 | { | 4985 | { |
| 4869 | struct ipc_security_struct *isec; | 4986 | struct ipc_security_struct *isec; |
| 4870 | struct avc_audit_data ad; | 4987 | struct common_audit_data ad; |
| 4871 | u32 sid = current_sid(); | 4988 | u32 sid = current_sid(); |
| 4872 | 4989 | ||
| 4873 | isec = shp->shm_perm.security; | 4990 | isec = shp->shm_perm.security; |
| 4874 | 4991 | ||
| 4875 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4992 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4876 | ad.u.ipc_id = shp->shm_perm.key; | 4993 | ad.u.ipc_id = shp->shm_perm.key; |
| 4877 | 4994 | ||
| 4878 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 4995 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
| @@ -4929,7 +5046,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, | |||
| 4929 | static int selinux_sem_alloc_security(struct sem_array *sma) | 5046 | static int selinux_sem_alloc_security(struct sem_array *sma) |
| 4930 | { | 5047 | { |
| 4931 | struct ipc_security_struct *isec; | 5048 | struct ipc_security_struct *isec; |
| 4932 | struct avc_audit_data ad; | 5049 | struct common_audit_data ad; |
| 4933 | u32 sid = current_sid(); | 5050 | u32 sid = current_sid(); |
| 4934 | int rc; | 5051 | int rc; |
| 4935 | 5052 | ||
| @@ -4939,7 +5056,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) | |||
| 4939 | 5056 | ||
| 4940 | isec = sma->sem_perm.security; | 5057 | isec = sma->sem_perm.security; |
| 4941 | 5058 | ||
| 4942 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 5059 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4943 | ad.u.ipc_id = sma->sem_perm.key; | 5060 | ad.u.ipc_id = sma->sem_perm.key; |
| 4944 | 5061 | ||
| 4945 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5062 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
| @@ -4959,12 +5076,12 @@ static void selinux_sem_free_security(struct sem_array *sma) | |||
| 4959 | static int selinux_sem_associate(struct sem_array *sma, int semflg) | 5076 | static int selinux_sem_associate(struct sem_array *sma, int semflg) |
| 4960 | { | 5077 | { |
| 4961 | struct ipc_security_struct *isec; | 5078 | struct ipc_security_struct *isec; |
| 4962 | struct avc_audit_data ad; | 5079 | struct common_audit_data ad; |
| 4963 | u32 sid = current_sid(); | 5080 | u32 sid = current_sid(); |
| 4964 | 5081 | ||
| 4965 | isec = sma->sem_perm.security; | 5082 | isec = sma->sem_perm.security; |
| 4966 | 5083 | ||
| 4967 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 5084 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4968 | ad.u.ipc_id = sma->sem_perm.key; | 5085 | ad.u.ipc_id = sma->sem_perm.key; |
| 4969 | 5086 | ||
| 4970 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5087 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
| @@ -5182,7 +5299,7 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 5182 | 5299 | ||
| 5183 | /* Only allow single threaded processes to change context */ | 5300 | /* Only allow single threaded processes to change context */ |
| 5184 | error = -EPERM; | 5301 | error = -EPERM; |
| 5185 | if (!is_single_threaded(p)) { | 5302 | if (!current_is_single_threaded()) { |
| 5186 | error = security_bounded_transition(tsec->sid, sid); | 5303 | error = security_bounded_transition(tsec->sid, sid); |
| 5187 | if (error) | 5304 | if (error) |
| 5188 | goto abort_change; | 5305 | goto abort_change; |
| @@ -5239,6 +5356,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen) | |||
| 5239 | kfree(secdata); | 5356 | kfree(secdata); |
| 5240 | } | 5357 | } |
| 5241 | 5358 | ||
| 5359 | /* | ||
| 5360 | * called with inode->i_mutex locked | ||
| 5361 | */ | ||
| 5362 | static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 5363 | { | ||
| 5364 | return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0); | ||
| 5365 | } | ||
| 5366 | |||
| 5367 | /* | ||
| 5368 | * called with inode->i_mutex locked | ||
| 5369 | */ | ||
| 5370 | static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 5371 | { | ||
| 5372 | return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0); | ||
| 5373 | } | ||
| 5374 | |||
| 5375 | static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 5376 | { | ||
| 5377 | int len = 0; | ||
| 5378 | len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX, | ||
| 5379 | ctx, true); | ||
| 5380 | if (len < 0) | ||
| 5381 | return len; | ||
| 5382 | *ctxlen = len; | ||
| 5383 | return 0; | ||
| 5384 | } | ||
| 5242 | #ifdef CONFIG_KEYS | 5385 | #ifdef CONFIG_KEYS |
| 5243 | 5386 | ||
| 5244 | static int selinux_key_alloc(struct key *k, const struct cred *cred, | 5387 | static int selinux_key_alloc(struct key *k, const struct cred *cred, |
| @@ -5310,7 +5453,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) | |||
| 5310 | static struct security_operations selinux_ops = { | 5453 | static struct security_operations selinux_ops = { |
| 5311 | .name = "selinux", | 5454 | .name = "selinux", |
| 5312 | 5455 | ||
| 5313 | .ptrace_may_access = selinux_ptrace_may_access, | 5456 | .ptrace_access_check = selinux_ptrace_access_check, |
| 5314 | .ptrace_traceme = selinux_ptrace_traceme, | 5457 | .ptrace_traceme = selinux_ptrace_traceme, |
| 5315 | .capget = selinux_capget, | 5458 | .capget = selinux_capget, |
| 5316 | .capset = selinux_capset, | 5459 | .capset = selinux_capset, |
| @@ -5383,10 +5526,13 @@ static struct security_operations selinux_ops = { | |||
| 5383 | .dentry_open = selinux_dentry_open, | 5526 | .dentry_open = selinux_dentry_open, |
| 5384 | 5527 | ||
| 5385 | .task_create = selinux_task_create, | 5528 | .task_create = selinux_task_create, |
| 5529 | .cred_alloc_blank = selinux_cred_alloc_blank, | ||
| 5386 | .cred_free = selinux_cred_free, | 5530 | .cred_free = selinux_cred_free, |
| 5387 | .cred_prepare = selinux_cred_prepare, | 5531 | .cred_prepare = selinux_cred_prepare, |
| 5532 | .cred_transfer = selinux_cred_transfer, | ||
| 5388 | .kernel_act_as = selinux_kernel_act_as, | 5533 | .kernel_act_as = selinux_kernel_act_as, |
| 5389 | .kernel_create_files_as = selinux_kernel_create_files_as, | 5534 | .kernel_create_files_as = selinux_kernel_create_files_as, |
| 5535 | .kernel_module_request = selinux_kernel_module_request, | ||
| 5390 | .task_setpgid = selinux_task_setpgid, | 5536 | .task_setpgid = selinux_task_setpgid, |
| 5391 | .task_getpgid = selinux_task_getpgid, | 5537 | .task_getpgid = selinux_task_getpgid, |
| 5392 | .task_getsid = selinux_task_getsid, | 5538 | .task_getsid = selinux_task_getsid, |
| @@ -5435,6 +5581,9 @@ static struct security_operations selinux_ops = { | |||
| 5435 | .secid_to_secctx = selinux_secid_to_secctx, | 5581 | .secid_to_secctx = selinux_secid_to_secctx, |
| 5436 | .secctx_to_secid = selinux_secctx_to_secid, | 5582 | .secctx_to_secid = selinux_secctx_to_secid, |
| 5437 | .release_secctx = selinux_release_secctx, | 5583 | .release_secctx = selinux_release_secctx, |
| 5584 | .inode_notifysecctx = selinux_inode_notifysecctx, | ||
| 5585 | .inode_setsecctx = selinux_inode_setsecctx, | ||
| 5586 | .inode_getsecctx = selinux_inode_getsecctx, | ||
| 5438 | 5587 | ||
| 5439 | .unix_stream_connect = selinux_socket_unix_stream_connect, | 5588 | .unix_stream_connect = selinux_socket_unix_stream_connect, |
| 5440 | .unix_may_send = selinux_socket_unix_may_send, | 5589 | .unix_may_send = selinux_socket_unix_may_send, |
| @@ -5464,6 +5613,9 @@ static struct security_operations selinux_ops = { | |||
| 5464 | .inet_csk_clone = selinux_inet_csk_clone, | 5613 | .inet_csk_clone = selinux_inet_csk_clone, |
| 5465 | .inet_conn_established = selinux_inet_conn_established, | 5614 | .inet_conn_established = selinux_inet_conn_established, |
| 5466 | .req_classify_flow = selinux_req_classify_flow, | 5615 | .req_classify_flow = selinux_req_classify_flow, |
| 5616 | .tun_dev_create = selinux_tun_dev_create, | ||
| 5617 | .tun_dev_post_create = selinux_tun_dev_post_create, | ||
| 5618 | .tun_dev_attach = selinux_tun_dev_attach, | ||
| 5467 | 5619 | ||
| 5468 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 5620 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 5469 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 5621 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |
| @@ -5678,6 +5830,9 @@ int selinux_disable(void) | |||
| 5678 | selinux_disabled = 1; | 5830 | selinux_disabled = 1; |
| 5679 | selinux_enabled = 0; | 5831 | selinux_enabled = 0; |
| 5680 | 5832 | ||
| 5833 | /* Try to destroy the avc node cache */ | ||
| 5834 | avc_disable(); | ||
| 5835 | |||
| 5681 | /* Reset security_ops to the secondary module, dummy or capability. */ | 5836 | /* Reset security_ops to the secondary module, dummy or capability. */ |
| 5682 | security_ops = secondary_ops; | 5837 | security_ops = secondary_ops; |
| 5683 | 5838 | ||
diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h index 8377a4ba3b95..abedcd704dae 100644 --- a/security/selinux/include/av_inherit.h +++ b/security/selinux/include/av_inherit.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL) | 15 | S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL) |
| 16 | S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL) | 16 | S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL) |
| 17 | S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL) | 17 | S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL) |
| 18 | S_(SECCLASS_TUN_SOCKET, socket, 0x00400000UL) | ||
| 18 | S_(SECCLASS_IPC, ipc, 0x00000200UL) | 19 | S_(SECCLASS_IPC, ipc, 0x00000200UL) |
| 19 | S_(SECCLASS_SEM, ipc, 0x00000200UL) | 20 | S_(SECCLASS_SEM, ipc, 0x00000200UL) |
| 20 | S_(SECCLASS_MSGQ, ipc, 0x00000200UL) | 21 | S_(SECCLASS_MSGQ, ipc, 0x00000200UL) |
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 31df1d7c1aee..2b683ad83d21 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h | |||
| @@ -107,6 +107,7 @@ | |||
| 107 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") | 107 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") |
| 108 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") | 108 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") |
| 109 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") | 109 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") |
| 110 | S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request") | ||
| 110 | S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") | 111 | S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") |
| 111 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override") | 112 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override") |
| 112 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search") | 113 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search") |
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index d645192ee950..0546d616ccac 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h | |||
| @@ -423,6 +423,28 @@ | |||
| 423 | #define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL | 423 | #define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL |
| 424 | #define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL | 424 | #define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL |
| 425 | #define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL | 425 | #define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL |
| 426 | #define TUN_SOCKET__IOCTL 0x00000001UL | ||
| 427 | #define TUN_SOCKET__READ 0x00000002UL | ||
| 428 | #define TUN_SOCKET__WRITE 0x00000004UL | ||
| 429 | #define TUN_SOCKET__CREATE 0x00000008UL | ||
| 430 | #define TUN_SOCKET__GETATTR 0x00000010UL | ||
| 431 | #define TUN_SOCKET__SETATTR 0x00000020UL | ||
| 432 | #define TUN_SOCKET__LOCK 0x00000040UL | ||
| 433 | #define TUN_SOCKET__RELABELFROM 0x00000080UL | ||
| 434 | #define TUN_SOCKET__RELABELTO 0x00000100UL | ||
| 435 | #define TUN_SOCKET__APPEND 0x00000200UL | ||
| 436 | #define TUN_SOCKET__BIND 0x00000400UL | ||
| 437 | #define TUN_SOCKET__CONNECT 0x00000800UL | ||
| 438 | #define TUN_SOCKET__LISTEN 0x00001000UL | ||
| 439 | #define TUN_SOCKET__ACCEPT 0x00002000UL | ||
| 440 | #define TUN_SOCKET__GETOPT 0x00004000UL | ||
| 441 | #define TUN_SOCKET__SETOPT 0x00008000UL | ||
| 442 | #define TUN_SOCKET__SHUTDOWN 0x00010000UL | ||
| 443 | #define TUN_SOCKET__RECVFROM 0x00020000UL | ||
| 444 | #define TUN_SOCKET__SENDTO 0x00040000UL | ||
| 445 | #define TUN_SOCKET__RECV_MSG 0x00080000UL | ||
| 446 | #define TUN_SOCKET__SEND_MSG 0x00100000UL | ||
| 447 | #define TUN_SOCKET__NAME_BIND 0x00200000UL | ||
| 426 | #define PROCESS__FORK 0x00000001UL | 448 | #define PROCESS__FORK 0x00000001UL |
| 427 | #define PROCESS__TRANSITION 0x00000002UL | 449 | #define PROCESS__TRANSITION 0x00000002UL |
| 428 | #define PROCESS__SIGCHLD 0x00000004UL | 450 | #define PROCESS__SIGCHLD 0x00000004UL |
| @@ -508,6 +530,7 @@ | |||
| 508 | #define SYSTEM__SYSLOG_READ 0x00000002UL | 530 | #define SYSTEM__SYSLOG_READ 0x00000002UL |
| 509 | #define SYSTEM__SYSLOG_MOD 0x00000004UL | 531 | #define SYSTEM__SYSLOG_MOD 0x00000004UL |
| 510 | #define SYSTEM__SYSLOG_CONSOLE 0x00000008UL | 532 | #define SYSTEM__SYSLOG_CONSOLE 0x00000008UL |
| 533 | #define SYSTEM__MODULE_REQUEST 0x00000010UL | ||
| 511 | #define CAPABILITY__CHOWN 0x00000001UL | 534 | #define CAPABILITY__CHOWN 0x00000001UL |
| 512 | #define CAPABILITY__DAC_OVERRIDE 0x00000002UL | 535 | #define CAPABILITY__DAC_OVERRIDE 0x00000002UL |
| 513 | #define CAPABILITY__DAC_READ_SEARCH 0x00000004UL | 536 | #define CAPABILITY__DAC_READ_SEARCH 0x00000004UL |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index d12ff1a9c0aa..e94e82f73818 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/audit.h> | 15 | #include <linux/audit.h> |
| 16 | #include <linux/lsm_audit.h> | ||
| 16 | #include <linux/in6.h> | 17 | #include <linux/in6.h> |
| 17 | #include <linux/path.h> | 18 | #include <linux/path.h> |
| 18 | #include <asm/system.h> | 19 | #include <asm/system.h> |
| @@ -36,48 +37,6 @@ struct inode; | |||
| 36 | struct sock; | 37 | struct sock; |
| 37 | struct sk_buff; | 38 | struct sk_buff; |
| 38 | 39 | ||
| 39 | /* Auxiliary data to use in generating the audit record. */ | ||
| 40 | struct avc_audit_data { | ||
| 41 | char type; | ||
| 42 | #define AVC_AUDIT_DATA_FS 1 | ||
| 43 | #define AVC_AUDIT_DATA_NET 2 | ||
| 44 | #define AVC_AUDIT_DATA_CAP 3 | ||
| 45 | #define AVC_AUDIT_DATA_IPC 4 | ||
| 46 | struct task_struct *tsk; | ||
| 47 | union { | ||
| 48 | struct { | ||
| 49 | struct path path; | ||
| 50 | struct inode *inode; | ||
| 51 | } fs; | ||
| 52 | struct { | ||
| 53 | int netif; | ||
| 54 | struct sock *sk; | ||
| 55 | u16 family; | ||
| 56 | __be16 dport; | ||
| 57 | __be16 sport; | ||
| 58 | union { | ||
| 59 | struct { | ||
| 60 | __be32 daddr; | ||
| 61 | __be32 saddr; | ||
| 62 | } v4; | ||
| 63 | struct { | ||
| 64 | struct in6_addr daddr; | ||
| 65 | struct in6_addr saddr; | ||
| 66 | } v6; | ||
| 67 | } fam; | ||
| 68 | } net; | ||
| 69 | int cap; | ||
| 70 | int ipc_id; | ||
| 71 | } u; | ||
| 72 | }; | ||
| 73 | |||
| 74 | #define v4info fam.v4 | ||
| 75 | #define v6info fam.v6 | ||
| 76 | |||
| 77 | /* Initialize an AVC audit data structure. */ | ||
| 78 | #define AVC_AUDIT_DATA_INIT(_d,_t) \ | ||
| 79 | { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } | ||
| 80 | |||
| 81 | /* | 40 | /* |
| 82 | * AVC statistics | 41 | * AVC statistics |
| 83 | */ | 42 | */ |
| @@ -98,7 +57,9 @@ void __init avc_init(void); | |||
| 98 | 57 | ||
| 99 | void avc_audit(u32 ssid, u32 tsid, | 58 | void avc_audit(u32 ssid, u32 tsid, |
| 100 | u16 tclass, u32 requested, | 59 | u16 tclass, u32 requested, |
| 101 | struct av_decision *avd, int result, struct avc_audit_data *auditdata); | 60 | struct av_decision *avd, |
| 61 | int result, | ||
| 62 | struct common_audit_data *a); | ||
| 102 | 63 | ||
| 103 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 64 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
| 104 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 65 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
| @@ -108,7 +69,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
| 108 | 69 | ||
| 109 | int avc_has_perm(u32 ssid, u32 tsid, | 70 | int avc_has_perm(u32 ssid, u32 tsid, |
| 110 | u16 tclass, u32 requested, | 71 | u16 tclass, u32 requested, |
| 111 | struct avc_audit_data *auditdata); | 72 | struct common_audit_data *auditdata); |
| 112 | 73 | ||
| 113 | u32 avc_policy_seqno(void); | 74 | u32 avc_policy_seqno(void); |
| 114 | 75 | ||
| @@ -127,13 +88,13 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
| 127 | u32 events, u32 ssid, u32 tsid, | 88 | u32 events, u32 ssid, u32 tsid, |
| 128 | u16 tclass, u32 perms); | 89 | u16 tclass, u32 perms); |
| 129 | 90 | ||
| 130 | /* Shows permission in human readable form */ | ||
| 131 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); | ||
| 132 | |||
| 133 | /* Exported to selinuxfs */ | 91 | /* Exported to selinuxfs */ |
| 134 | int avc_get_hash_stats(char *page); | 92 | int avc_get_hash_stats(char *page); |
| 135 | extern unsigned int avc_cache_threshold; | 93 | extern unsigned int avc_cache_threshold; |
| 136 | 94 | ||
| 95 | /* Attempt to free avc node cache */ | ||
| 96 | void avc_disable(void); | ||
| 97 | |||
| 137 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS | 98 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS |
| 138 | DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats); | 99 | DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats); |
| 139 | #endif | 100 | #endif |
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 21ec786611d4..7ab9299bfb6b 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h | |||
| @@ -77,3 +77,4 @@ | |||
| 77 | S_(NULL) | 77 | S_(NULL) |
| 78 | S_(NULL) | 78 | S_(NULL) |
| 79 | S_("kernel_service") | 79 | S_("kernel_service") |
| 80 | S_("tun_socket") | ||
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index 882f27d66fac..f248500a1e3c 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #define SECCLASS_PEER 68 | 53 | #define SECCLASS_PEER 68 |
| 54 | #define SECCLASS_CAPABILITY2 69 | 54 | #define SECCLASS_CAPABILITY2 69 |
| 55 | #define SECCLASS_KERNEL_SERVICE 74 | 55 | #define SECCLASS_KERNEL_SERVICE 74 |
| 56 | #define SECCLASS_TUN_SOCKET 75 | ||
| 56 | 57 | ||
| 57 | /* | 58 | /* |
| 58 | * Security identifier indices for initial entities | 59 | * Security identifier indices for initial entities |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b4b5b9b2f0be..8d7384280a7a 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -59,7 +59,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); | |||
| 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 60 | struct sk_buff *skb, | 60 | struct sk_buff *skb, |
| 61 | u16 family, | 61 | u16 family, |
| 62 | struct avc_audit_data *ad); | 62 | struct common_audit_data *ad); |
| 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
| 64 | int level, | 64 | int level, |
| 65 | int optname); | 65 | int optname); |
| @@ -129,7 +129,7 @@ static inline int selinux_netlbl_socket_post_create(struct sock *sk, | |||
| 129 | static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 129 | static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 130 | struct sk_buff *skb, | 130 | struct sk_buff *skb, |
| 131 | u16 family, | 131 | u16 family, |
| 132 | struct avc_audit_data *ad) | 132 | struct common_audit_data *ad) |
| 133 | { | 133 | { |
| 134 | return 0; | 134 | return 0; |
| 135 | } | 135 | } |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 289e24b39e3e..13128f9a3e5a 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
| @@ -41,9 +41,9 @@ static inline int selinux_xfrm_enabled(void) | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, | 43 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, |
| 44 | struct avc_audit_data *ad); | 44 | struct common_audit_data *ad); |
| 45 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 45 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
| 46 | struct avc_audit_data *ad, u8 proto); | 46 | struct common_audit_data *ad, u8 proto); |
| 47 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); | 47 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); |
| 48 | 48 | ||
| 49 | static inline void selinux_xfrm_notify_policyload(void) | 49 | static inline void selinux_xfrm_notify_policyload(void) |
| @@ -57,13 +57,13 @@ static inline int selinux_xfrm_enabled(void) | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | 59 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
| 60 | struct avc_audit_data *ad) | 60 | struct common_audit_data *ad) |
| 61 | { | 61 | { |
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 65 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
| 66 | struct avc_audit_data *ad, u8 proto) | 66 | struct common_audit_data *ad, u8 proto) |
| 67 | { | 67 | { |
| 68 | return 0; | 68 | return 0; |
| 69 | } | 69 | } |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2e984413c7b2..e68823741ad5 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -342,7 +342,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) | |||
| 342 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 342 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 343 | struct sk_buff *skb, | 343 | struct sk_buff *skb, |
| 344 | u16 family, | 344 | u16 family, |
| 345 | struct avc_audit_data *ad) | 345 | struct common_audit_data *ad) |
| 346 | { | 346 | { |
| 347 | int rc; | 347 | int rc; |
| 348 | u32 nlbl_sid; | 348 | u32 nlbl_sid; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 500e6f78e115..ff17820d35ec 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -22,6 +22,11 @@ | |||
| 22 | * | 22 | * |
| 23 | * Added validation of kernel classes and permissions | 23 | * Added validation of kernel classes and permissions |
| 24 | * | 24 | * |
| 25 | * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> | ||
| 26 | * | ||
| 27 | * Added support for bounds domain and audit messaged on masked permissions | ||
| 28 | * | ||
| 29 | * Copyright (C) 2008, 2009 NEC Corporation | ||
| 25 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 30 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
| 26 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 31 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
| 27 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC | 32 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC |
| @@ -279,6 +284,95 @@ mls_ops: | |||
| 279 | } | 284 | } |
| 280 | 285 | ||
| 281 | /* | 286 | /* |
| 287 | * security_dump_masked_av - dumps masked permissions during | ||
| 288 | * security_compute_av due to RBAC, MLS/Constraint and Type bounds. | ||
| 289 | */ | ||
| 290 | static int dump_masked_av_helper(void *k, void *d, void *args) | ||
| 291 | { | ||
| 292 | struct perm_datum *pdatum = d; | ||
| 293 | char **permission_names = args; | ||
| 294 | |||
| 295 | BUG_ON(pdatum->value < 1 || pdatum->value > 32); | ||
| 296 | |||
| 297 | permission_names[pdatum->value - 1] = (char *)k; | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static void security_dump_masked_av(struct context *scontext, | ||
| 303 | struct context *tcontext, | ||
| 304 | u16 tclass, | ||
| 305 | u32 permissions, | ||
| 306 | const char *reason) | ||
| 307 | { | ||
| 308 | struct common_datum *common_dat; | ||
| 309 | struct class_datum *tclass_dat; | ||
| 310 | struct audit_buffer *ab; | ||
| 311 | char *tclass_name; | ||
| 312 | char *scontext_name = NULL; | ||
| 313 | char *tcontext_name = NULL; | ||
| 314 | char *permission_names[32]; | ||
| 315 | int index, length; | ||
| 316 | bool need_comma = false; | ||
| 317 | |||
| 318 | if (!permissions) | ||
| 319 | return; | ||
| 320 | |||
| 321 | tclass_name = policydb.p_class_val_to_name[tclass - 1]; | ||
| 322 | tclass_dat = policydb.class_val_to_struct[tclass - 1]; | ||
| 323 | common_dat = tclass_dat->comdatum; | ||
| 324 | |||
| 325 | /* init permission_names */ | ||
| 326 | if (common_dat && | ||
| 327 | hashtab_map(common_dat->permissions.table, | ||
| 328 | dump_masked_av_helper, permission_names) < 0) | ||
| 329 | goto out; | ||
| 330 | |||
| 331 | if (hashtab_map(tclass_dat->permissions.table, | ||
| 332 | dump_masked_av_helper, permission_names) < 0) | ||
| 333 | goto out; | ||
| 334 | |||
| 335 | /* get scontext/tcontext in text form */ | ||
| 336 | if (context_struct_to_string(scontext, | ||
| 337 | &scontext_name, &length) < 0) | ||
| 338 | goto out; | ||
| 339 | |||
| 340 | if (context_struct_to_string(tcontext, | ||
| 341 | &tcontext_name, &length) < 0) | ||
| 342 | goto out; | ||
| 343 | |||
| 344 | /* audit a message */ | ||
| 345 | ab = audit_log_start(current->audit_context, | ||
| 346 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
| 347 | if (!ab) | ||
| 348 | goto out; | ||
| 349 | |||
| 350 | audit_log_format(ab, "op=security_compute_av reason=%s " | ||
| 351 | "scontext=%s tcontext=%s tclass=%s perms=", | ||
| 352 | reason, scontext_name, tcontext_name, tclass_name); | ||
| 353 | |||
| 354 | for (index = 0; index < 32; index++) { | ||
| 355 | u32 mask = (1 << index); | ||
| 356 | |||
| 357 | if ((mask & permissions) == 0) | ||
| 358 | continue; | ||
| 359 | |||
| 360 | audit_log_format(ab, "%s%s", | ||
| 361 | need_comma ? "," : "", | ||
| 362 | permission_names[index] | ||
| 363 | ? permission_names[index] : "????"); | ||
| 364 | need_comma = true; | ||
| 365 | } | ||
| 366 | audit_log_end(ab); | ||
| 367 | out: | ||
| 368 | /* release scontext/tcontext */ | ||
| 369 | kfree(tcontext_name); | ||
| 370 | kfree(scontext_name); | ||
| 371 | |||
| 372 | return; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* | ||
| 282 | * security_boundary_permission - drops violated permissions | 376 | * security_boundary_permission - drops violated permissions |
| 283 | * on boundary constraint. | 377 | * on boundary constraint. |
| 284 | */ | 378 | */ |
| @@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 347 | } | 441 | } |
| 348 | 442 | ||
| 349 | if (masked) { | 443 | if (masked) { |
| 350 | struct audit_buffer *ab; | ||
| 351 | char *stype_name | ||
| 352 | = policydb.p_type_val_to_name[source->value - 1]; | ||
| 353 | char *ttype_name | ||
| 354 | = policydb.p_type_val_to_name[target->value - 1]; | ||
| 355 | char *tclass_name | ||
| 356 | = policydb.p_class_val_to_name[tclass - 1]; | ||
| 357 | |||
| 358 | /* mask violated permissions */ | 444 | /* mask violated permissions */ |
| 359 | avd->allowed &= ~masked; | 445 | avd->allowed &= ~masked; |
| 360 | 446 | ||
| 361 | /* notice to userspace via audit message */ | 447 | /* audit masked permissions */ |
| 362 | ab = audit_log_start(current->audit_context, | 448 | security_dump_masked_av(scontext, tcontext, |
| 363 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | 449 | tclass, masked, "bounds"); |
| 364 | if (!ab) | ||
| 365 | return; | ||
| 366 | |||
| 367 | audit_log_format(ab, "av boundary violation: " | ||
| 368 | "source=%s target=%s tclass=%s", | ||
| 369 | stype_name, ttype_name, tclass_name); | ||
| 370 | avc_dump_av(ab, tclass, masked); | ||
| 371 | audit_log_end(ab); | ||
| 372 | } | 450 | } |
| 373 | } | 451 | } |
| 374 | 452 | ||
| @@ -480,7 +558,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
| 480 | if ((constraint->permissions & (avd->allowed)) && | 558 | if ((constraint->permissions & (avd->allowed)) && |
| 481 | !constraint_expr_eval(scontext, tcontext, NULL, | 559 | !constraint_expr_eval(scontext, tcontext, NULL, |
| 482 | constraint->expr)) { | 560 | constraint->expr)) { |
| 483 | avd->allowed = (avd->allowed) & ~(constraint->permissions); | 561 | avd->allowed &= ~(constraint->permissions); |
| 484 | } | 562 | } |
| 485 | constraint = constraint->next; | 563 | constraint = constraint->next; |
| 486 | } | 564 | } |
| @@ -499,8 +577,8 @@ static int context_struct_compute_av(struct context *scontext, | |||
| 499 | break; | 577 | break; |
| 500 | } | 578 | } |
| 501 | if (!ra) | 579 | if (!ra) |
| 502 | avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | | 580 | avd->allowed &= ~(PROCESS__TRANSITION | |
| 503 | PROCESS__DYNTRANSITION); | 581 | PROCESS__DYNTRANSITION); |
| 504 | } | 582 | } |
| 505 | 583 | ||
| 506 | /* | 584 | /* |
| @@ -687,6 +765,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) | |||
| 687 | } | 765 | } |
| 688 | index = type->bounds; | 766 | index = type->bounds; |
| 689 | } | 767 | } |
| 768 | |||
| 769 | if (rc) { | ||
| 770 | char *old_name = NULL; | ||
| 771 | char *new_name = NULL; | ||
| 772 | int length; | ||
| 773 | |||
| 774 | if (!context_struct_to_string(old_context, | ||
| 775 | &old_name, &length) && | ||
| 776 | !context_struct_to_string(new_context, | ||
| 777 | &new_name, &length)) { | ||
| 778 | audit_log(current->audit_context, | ||
| 779 | GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
| 780 | "op=security_bounded_transition " | ||
| 781 | "result=denied " | ||
| 782 | "oldcontext=%s newcontext=%s", | ||
| 783 | old_name, new_name); | ||
| 784 | } | ||
| 785 | kfree(new_name); | ||
| 786 | kfree(old_name); | ||
| 787 | } | ||
| 690 | out: | 788 | out: |
| 691 | read_unlock(&policy_rwlock); | 789 | read_unlock(&policy_rwlock); |
| 692 | 790 | ||
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 72b18452e1a1..f3cb9ed731a9 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
| @@ -401,7 +401,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) | |||
| 401 | * gone thru the IPSec process. | 401 | * gone thru the IPSec process. |
| 402 | */ | 402 | */ |
| 403 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | 403 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
| 404 | struct avc_audit_data *ad) | 404 | struct common_audit_data *ad) |
| 405 | { | 405 | { |
| 406 | int i, rc = 0; | 406 | int i, rc = 0; |
| 407 | struct sec_path *sp; | 407 | struct sec_path *sp; |
| @@ -442,7 +442,7 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | |||
| 442 | * checked in the selinux_xfrm_state_pol_flow_match hook above. | 442 | * checked in the selinux_xfrm_state_pol_flow_match hook above. |
| 443 | */ | 443 | */ |
| 444 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 444 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
| 445 | struct avc_audit_data *ad, u8 proto) | 445 | struct common_audit_data *ad, u8 proto) |
| 446 | { | 446 | { |
| 447 | struct dst_entry *dst; | 447 | struct dst_entry *dst; |
| 448 | int rc = 0; | 448 | int rc = 0; |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 243bec175be0..c6e9acae72e4 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
| @@ -275,7 +275,7 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func, | |||
| 275 | { | 275 | { |
| 276 | memset(a, 0, sizeof(*a)); | 276 | memset(a, 0, sizeof(*a)); |
| 277 | a->a.type = type; | 277 | a->a.type = type; |
| 278 | a->a.function = func; | 278 | a->a.smack_audit_data.function = func; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, | 281 | static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 513dc1aa16dd..0f9ac8146900 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
| @@ -240,8 +240,9 @@ static inline void smack_str_from_perm(char *string, int access) | |||
| 240 | static void smack_log_callback(struct audit_buffer *ab, void *a) | 240 | static void smack_log_callback(struct audit_buffer *ab, void *a) |
| 241 | { | 241 | { |
| 242 | struct common_audit_data *ad = a; | 242 | struct common_audit_data *ad = a; |
| 243 | struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data; | 243 | struct smack_audit_data *sad = &ad->smack_audit_data; |
| 244 | audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function, | 244 | audit_log_format(ab, "lsm=SMACK fn=%s action=%s", |
| 245 | ad->smack_audit_data.function, | ||
| 245 | sad->result ? "denied" : "granted"); | 246 | sad->result ? "denied" : "granted"); |
| 246 | audit_log_format(ab, " subject="); | 247 | audit_log_format(ab, " subject="); |
| 247 | audit_log_untrustedstring(ab, sad->subject); | 248 | audit_log_untrustedstring(ab, sad->subject); |
| @@ -274,11 +275,11 @@ void smack_log(char *subject_label, char *object_label, int request, | |||
| 274 | if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) | 275 | if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) |
| 275 | return; | 276 | return; |
| 276 | 277 | ||
| 277 | if (a->function == NULL) | 278 | if (a->smack_audit_data.function == NULL) |
| 278 | a->function = "unknown"; | 279 | a->smack_audit_data.function = "unknown"; |
| 279 | 280 | ||
| 280 | /* end preparing the audit data */ | 281 | /* end preparing the audit data */ |
| 281 | sad = &a->lsm_priv.smack_audit_data; | 282 | sad = &a->smack_audit_data; |
| 282 | smack_str_from_perm(request_buffer, request); | 283 | smack_str_from_perm(request_buffer, request); |
| 283 | sad->subject = subject_label; | 284 | sad->subject = subject_label; |
| 284 | sad->object = object_label; | 285 | sad->object = object_label; |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0023182078c7..c33b6bb9b6dd 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -30,17 +30,11 @@ | |||
| 30 | #include <net/netlabel.h> | 30 | #include <net/netlabel.h> |
| 31 | #include <net/cipso_ipv4.h> | 31 | #include <net/cipso_ipv4.h> |
| 32 | #include <linux/audit.h> | 32 | #include <linux/audit.h> |
| 33 | #include <linux/magic.h> | ||
| 33 | #include "smack.h" | 34 | #include "smack.h" |
| 34 | 35 | ||
| 35 | #define task_security(task) (task_cred_xxx((task), security)) | 36 | #define task_security(task) (task_cred_xxx((task), security)) |
| 36 | 37 | ||
| 37 | /* | ||
| 38 | * I hope these are the hokeyist lines of code in the module. Casey. | ||
| 39 | */ | ||
| 40 | #define DEVPTS_SUPER_MAGIC 0x1cd1 | ||
| 41 | #define SOCKFS_MAGIC 0x534F434B | ||
| 42 | #define TMPFS_MAGIC 0x01021994 | ||
| 43 | |||
| 44 | /** | 38 | /** |
| 45 | * smk_fetch - Fetch the smack label from a file. | 39 | * smk_fetch - Fetch the smack label from a file. |
| 46 | * @ip: a pointer to the inode | 40 | * @ip: a pointer to the inode |
| @@ -91,7 +85,7 @@ struct inode_smack *new_inode_smack(char *smack) | |||
| 91 | */ | 85 | */ |
| 92 | 86 | ||
| 93 | /** | 87 | /** |
| 94 | * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH | 88 | * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH |
| 95 | * @ctp: child task pointer | 89 | * @ctp: child task pointer |
| 96 | * @mode: ptrace attachment mode | 90 | * @mode: ptrace attachment mode |
| 97 | * | 91 | * |
| @@ -99,13 +93,13 @@ struct inode_smack *new_inode_smack(char *smack) | |||
| 99 | * | 93 | * |
| 100 | * Do the capability checks, and require read and write. | 94 | * Do the capability checks, and require read and write. |
| 101 | */ | 95 | */ |
| 102 | static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) | 96 | static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) |
| 103 | { | 97 | { |
| 104 | int rc; | 98 | int rc; |
| 105 | struct smk_audit_info ad; | 99 | struct smk_audit_info ad; |
| 106 | char *sp, *tsp; | 100 | char *sp, *tsp; |
| 107 | 101 | ||
| 108 | rc = cap_ptrace_may_access(ctp, mode); | 102 | rc = cap_ptrace_access_check(ctp, mode); |
| 109 | if (rc != 0) | 103 | if (rc != 0) |
| 110 | return rc; | 104 | return rc; |
| 111 | 105 | ||
| @@ -1080,6 +1074,22 @@ static int smack_file_receive(struct file *file) | |||
| 1080 | */ | 1074 | */ |
| 1081 | 1075 | ||
| 1082 | /** | 1076 | /** |
| 1077 | * smack_cred_alloc_blank - "allocate" blank task-level security credentials | ||
| 1078 | * @new: the new credentials | ||
| 1079 | * @gfp: the atomicity of any memory allocations | ||
| 1080 | * | ||
| 1081 | * Prepare a blank set of credentials for modification. This must allocate all | ||
| 1082 | * the memory the LSM module might require such that cred_transfer() can | ||
| 1083 | * complete without error. | ||
| 1084 | */ | ||
| 1085 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 1086 | { | ||
| 1087 | cred->security = NULL; | ||
| 1088 | return 0; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | |||
| 1092 | /** | ||
| 1083 | * smack_cred_free - "free" task-level security credentials | 1093 | * smack_cred_free - "free" task-level security credentials |
| 1084 | * @cred: the credentials in question | 1094 | * @cred: the credentials in question |
| 1085 | * | 1095 | * |
| @@ -1117,6 +1127,18 @@ static void smack_cred_commit(struct cred *new, const struct cred *old) | |||
| 1117 | } | 1127 | } |
| 1118 | 1128 | ||
| 1119 | /** | 1129 | /** |
| 1130 | * smack_cred_transfer - Transfer the old credentials to the new credentials | ||
| 1131 | * @new: the new credentials | ||
| 1132 | * @old: the original credentials | ||
| 1133 | * | ||
| 1134 | * Fill in a set of blank credentials from another set of credentials. | ||
| 1135 | */ | ||
| 1136 | static void smack_cred_transfer(struct cred *new, const struct cred *old) | ||
| 1137 | { | ||
| 1138 | new->security = old->security; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | /** | ||
| 1120 | * smack_kernel_act_as - Set the subjective context in a set of credentials | 1142 | * smack_kernel_act_as - Set the subjective context in a set of credentials |
| 1121 | * @new: points to the set of credentials to be modified. | 1143 | * @new: points to the set of credentials to be modified. |
| 1122 | * @secid: specifies the security ID to be set | 1144 | * @secid: specifies the security ID to be set |
| @@ -1638,6 +1660,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
| 1638 | 1660 | ||
| 1639 | if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { | 1661 | if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { |
| 1640 | nsp->smk_inode = sp; | 1662 | nsp->smk_inode = sp; |
| 1663 | nsp->smk_flags |= SMK_INODE_INSTANT; | ||
| 1641 | return 0; | 1664 | return 0; |
| 1642 | } | 1665 | } |
| 1643 | /* | 1666 | /* |
| @@ -2464,7 +2487,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
| 2464 | /* | 2487 | /* |
| 2465 | * Perfectly reasonable for this to be NULL | 2488 | * Perfectly reasonable for this to be NULL |
| 2466 | */ | 2489 | */ |
| 2467 | if (sip == NULL || sip->sin_family != PF_INET) | 2490 | if (sip == NULL || sip->sin_family != AF_INET) |
| 2468 | return 0; | 2491 | return 0; |
| 2469 | 2492 | ||
| 2470 | return smack_netlabel_send(sock->sk, sip); | 2493 | return smack_netlabel_send(sock->sk, sip); |
| @@ -3029,10 +3052,31 @@ static void smack_release_secctx(char *secdata, u32 seclen) | |||
| 3029 | { | 3052 | { |
| 3030 | } | 3053 | } |
| 3031 | 3054 | ||
| 3055 | static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 3056 | { | ||
| 3057 | return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0); | ||
| 3058 | } | ||
| 3059 | |||
| 3060 | static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 3061 | { | ||
| 3062 | return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0); | ||
| 3063 | } | ||
| 3064 | |||
| 3065 | static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 3066 | { | ||
| 3067 | int len = 0; | ||
| 3068 | len = smack_inode_getsecurity(inode, XATTR_SMACK_SUFFIX, ctx, true); | ||
| 3069 | |||
| 3070 | if (len < 0) | ||
| 3071 | return len; | ||
| 3072 | *ctxlen = len; | ||
| 3073 | return 0; | ||
| 3074 | } | ||
| 3075 | |||
| 3032 | struct security_operations smack_ops = { | 3076 | struct security_operations smack_ops = { |
| 3033 | .name = "smack", | 3077 | .name = "smack", |
| 3034 | 3078 | ||
| 3035 | .ptrace_may_access = smack_ptrace_may_access, | 3079 | .ptrace_access_check = smack_ptrace_access_check, |
| 3036 | .ptrace_traceme = smack_ptrace_traceme, | 3080 | .ptrace_traceme = smack_ptrace_traceme, |
| 3037 | .syslog = smack_syslog, | 3081 | .syslog = smack_syslog, |
| 3038 | 3082 | ||
| @@ -3073,9 +3117,11 @@ struct security_operations smack_ops = { | |||
| 3073 | .file_send_sigiotask = smack_file_send_sigiotask, | 3117 | .file_send_sigiotask = smack_file_send_sigiotask, |
| 3074 | .file_receive = smack_file_receive, | 3118 | .file_receive = smack_file_receive, |
| 3075 | 3119 | ||
| 3120 | .cred_alloc_blank = smack_cred_alloc_blank, | ||
| 3076 | .cred_free = smack_cred_free, | 3121 | .cred_free = smack_cred_free, |
| 3077 | .cred_prepare = smack_cred_prepare, | 3122 | .cred_prepare = smack_cred_prepare, |
| 3078 | .cred_commit = smack_cred_commit, | 3123 | .cred_commit = smack_cred_commit, |
| 3124 | .cred_transfer = smack_cred_transfer, | ||
| 3079 | .kernel_act_as = smack_kernel_act_as, | 3125 | .kernel_act_as = smack_kernel_act_as, |
| 3080 | .kernel_create_files_as = smack_kernel_create_files_as, | 3126 | .kernel_create_files_as = smack_kernel_create_files_as, |
| 3081 | .task_setpgid = smack_task_setpgid, | 3127 | .task_setpgid = smack_task_setpgid, |
| @@ -3155,6 +3201,9 @@ struct security_operations smack_ops = { | |||
| 3155 | .secid_to_secctx = smack_secid_to_secctx, | 3201 | .secid_to_secctx = smack_secid_to_secctx, |
| 3156 | .secctx_to_secid = smack_secctx_to_secid, | 3202 | .secctx_to_secid = smack_secctx_to_secid, |
| 3157 | .release_secctx = smack_release_secctx, | 3203 | .release_secctx = smack_release_secctx, |
| 3204 | .inode_notifysecctx = smack_inode_notifysecctx, | ||
| 3205 | .inode_setsecctx = smack_inode_setsecctx, | ||
| 3206 | .inode_getsecctx = smack_inode_getsecctx, | ||
| 3158 | }; | 3207 | }; |
| 3159 | 3208 | ||
| 3160 | 3209 | ||
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index f83a80980726..aeead7585093 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -187,7 +187,7 @@ static void load_seq_stop(struct seq_file *s, void *v) | |||
| 187 | /* No-op */ | 187 | /* No-op */ |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | static struct seq_operations load_seq_ops = { | 190 | static const struct seq_operations load_seq_ops = { |
| 191 | .start = load_seq_start, | 191 | .start = load_seq_start, |
| 192 | .next = load_seq_next, | 192 | .next = load_seq_next, |
| 193 | .show = load_seq_show, | 193 | .show = load_seq_show, |
| @@ -503,7 +503,7 @@ static void cipso_seq_stop(struct seq_file *s, void *v) | |||
| 503 | /* No-op */ | 503 | /* No-op */ |
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | static struct seq_operations cipso_seq_ops = { | 506 | static const struct seq_operations cipso_seq_ops = { |
| 507 | .start = cipso_seq_start, | 507 | .start = cipso_seq_start, |
| 508 | .stop = cipso_seq_stop, | 508 | .stop = cipso_seq_stop, |
| 509 | .next = cipso_seq_next, | 509 | .next = cipso_seq_next, |
| @@ -697,7 +697,7 @@ static void netlbladdr_seq_stop(struct seq_file *s, void *v) | |||
| 697 | /* No-op */ | 697 | /* No-op */ |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | static struct seq_operations netlbladdr_seq_ops = { | 700 | static const struct seq_operations netlbladdr_seq_ops = { |
| 701 | .start = netlbladdr_seq_start, | 701 | .start = netlbladdr_seq_start, |
| 702 | .stop = netlbladdr_seq_stop, | 702 | .stop = netlbladdr_seq_stop, |
| 703 | .next = netlbladdr_seq_next, | 703 | .next = netlbladdr_seq_next, |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index fdd1f4b8c448..3c8bd8ee0b95 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
| @@ -1285,6 +1285,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
| 1285 | } | 1285 | } |
| 1286 | 1286 | ||
| 1287 | /** | 1287 | /** |
| 1288 | * tomoyo_delete_domain - Delete a domain. | ||
| 1289 | * | ||
| 1290 | * @domainname: The name of domain. | ||
| 1291 | * | ||
| 1292 | * Returns 0. | ||
| 1293 | */ | ||
| 1294 | static int tomoyo_delete_domain(char *domainname) | ||
| 1295 | { | ||
| 1296 | struct tomoyo_domain_info *domain; | ||
| 1297 | struct tomoyo_path_info name; | ||
| 1298 | |||
| 1299 | name.name = domainname; | ||
| 1300 | tomoyo_fill_path_info(&name); | ||
| 1301 | down_write(&tomoyo_domain_list_lock); | ||
| 1302 | /* Is there an active domain? */ | ||
| 1303 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
| 1304 | /* Never delete tomoyo_kernel_domain */ | ||
| 1305 | if (domain == &tomoyo_kernel_domain) | ||
| 1306 | continue; | ||
| 1307 | if (domain->is_deleted || | ||
| 1308 | tomoyo_pathcmp(domain->domainname, &name)) | ||
| 1309 | continue; | ||
| 1310 | domain->is_deleted = true; | ||
| 1311 | break; | ||
| 1312 | } | ||
| 1313 | up_write(&tomoyo_domain_list_lock); | ||
| 1314 | return 0; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | /** | ||
| 1288 | * tomoyo_write_domain_policy - Write domain policy. | 1318 | * tomoyo_write_domain_policy - Write domain policy. |
| 1289 | * | 1319 | * |
| 1290 | * @head: Pointer to "struct tomoyo_io_buffer". | 1320 | * @head: Pointer to "struct tomoyo_io_buffer". |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6d6ba09af457..31df541911f7 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
| @@ -339,8 +339,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | |||
| 339 | const char *tomoyo_get_msg(const bool is_enforce); | 339 | const char *tomoyo_get_msg(const bool is_enforce); |
| 340 | /* Convert single path operation to operation name. */ | 340 | /* Convert single path operation to operation name. */ |
| 341 | const char *tomoyo_sp2keyword(const u8 operation); | 341 | const char *tomoyo_sp2keyword(const u8 operation); |
| 342 | /* Delete a domain. */ | ||
| 343 | int tomoyo_delete_domain(char *data); | ||
| 344 | /* Create "alias" entry in exception policy. */ | 342 | /* Create "alias" entry in exception policy. */ |
| 345 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 343 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
| 346 | /* | 344 | /* |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 1d8b16960576..fcf52accce2b 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
| @@ -717,38 +717,6 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) | |||
| 717 | return tomoyo_update_alias_entry(data, cp, is_delete); | 717 | return tomoyo_update_alias_entry(data, cp, is_delete); |
| 718 | } | 718 | } |
| 719 | 719 | ||
| 720 | /* Domain create/delete handler. */ | ||
| 721 | |||
| 722 | /** | ||
| 723 | * tomoyo_delete_domain - Delete a domain. | ||
| 724 | * | ||
| 725 | * @domainname: The name of domain. | ||
| 726 | * | ||
| 727 | * Returns 0. | ||
| 728 | */ | ||
| 729 | int tomoyo_delete_domain(char *domainname) | ||
| 730 | { | ||
| 731 | struct tomoyo_domain_info *domain; | ||
| 732 | struct tomoyo_path_info name; | ||
| 733 | |||
| 734 | name.name = domainname; | ||
| 735 | tomoyo_fill_path_info(&name); | ||
| 736 | down_write(&tomoyo_domain_list_lock); | ||
| 737 | /* Is there an active domain? */ | ||
| 738 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
| 739 | /* Never delete tomoyo_kernel_domain */ | ||
| 740 | if (domain == &tomoyo_kernel_domain) | ||
| 741 | continue; | ||
| 742 | if (domain->is_deleted || | ||
| 743 | tomoyo_pathcmp(domain->domainname, &name)) | ||
| 744 | continue; | ||
| 745 | domain->is_deleted = true; | ||
| 746 | break; | ||
| 747 | } | ||
| 748 | up_write(&tomoyo_domain_list_lock); | ||
| 749 | return 0; | ||
| 750 | } | ||
| 751 | |||
| 752 | /** | 720 | /** |
| 753 | * tomoyo_find_or_assign_new_domain - Create a domain. | 721 | * tomoyo_find_or_assign_new_domain - Create a domain. |
| 754 | * | 722 | * |
| @@ -818,13 +786,11 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
| 818 | /** | 786 | /** |
| 819 | * tomoyo_find_next_domain - Find a domain. | 787 | * tomoyo_find_next_domain - Find a domain. |
| 820 | * | 788 | * |
| 821 | * @bprm: Pointer to "struct linux_binprm". | 789 | * @bprm: Pointer to "struct linux_binprm". |
| 822 | * @next_domain: Pointer to pointer to "struct tomoyo_domain_info". | ||
| 823 | * | 790 | * |
| 824 | * Returns 0 on success, negative value otherwise. | 791 | * Returns 0 on success, negative value otherwise. |
| 825 | */ | 792 | */ |
| 826 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 793 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
| 827 | struct tomoyo_domain_info **next_domain) | ||
| 828 | { | 794 | { |
| 829 | /* | 795 | /* |
| 830 | * This function assumes that the size of buffer returned by | 796 | * This function assumes that the size of buffer returned by |
| @@ -946,9 +912,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, | |||
| 946 | tomoyo_set_domain_flag(old_domain, false, | 912 | tomoyo_set_domain_flag(old_domain, false, |
| 947 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | 913 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); |
| 948 | out: | 914 | out: |
| 915 | if (!domain) | ||
| 916 | domain = old_domain; | ||
| 917 | bprm->cred->security = domain; | ||
| 949 | tomoyo_free(real_program_name); | 918 | tomoyo_free(real_program_name); |
| 950 | tomoyo_free(symlink_program_name); | 919 | tomoyo_free(symlink_program_name); |
| 951 | *next_domain = domain ? domain : old_domain; | ||
| 952 | tomoyo_free(tmp); | 920 | tomoyo_free(tmp); |
| 953 | return retval; | 921 | return retval; |
| 954 | } | 922 | } |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 3194d09fe0f4..9548a0984cc4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
| @@ -14,6 +14,12 @@ | |||
| 14 | #include "tomoyo.h" | 14 | #include "tomoyo.h" |
| 15 | #include "realpath.h" | 15 | #include "realpath.h" |
| 16 | 16 | ||
| 17 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | ||
| 18 | { | ||
| 19 | new->security = NULL; | ||
| 20 | return 0; | ||
| 21 | } | ||
| 22 | |||
| 17 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 23 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
| 18 | gfp_t gfp) | 24 | gfp_t gfp) |
| 19 | { | 25 | { |
| @@ -25,6 +31,15 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | |||
| 25 | return 0; | 31 | return 0; |
| 26 | } | 32 | } |
| 27 | 33 | ||
| 34 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | ||
| 35 | { | ||
| 36 | /* | ||
| 37 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | ||
| 38 | * we don't need to duplicate. | ||
| 39 | */ | ||
| 40 | new->security = old->security; | ||
| 41 | } | ||
| 42 | |||
| 28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
| 29 | { | 44 | { |
| 30 | int rc; | 45 | int rc; |
| @@ -61,14 +76,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
| 61 | * Execute permission is checked against pathname passed to do_execve() | 76 | * Execute permission is checked against pathname passed to do_execve() |
| 62 | * using current domain. | 77 | * using current domain. |
| 63 | */ | 78 | */ |
| 64 | if (!domain) { | 79 | if (!domain) |
| 65 | struct tomoyo_domain_info *next_domain = NULL; | 80 | return tomoyo_find_next_domain(bprm); |
| 66 | int retval = tomoyo_find_next_domain(bprm, &next_domain); | ||
| 67 | |||
| 68 | if (!retval) | ||
| 69 | bprm->cred->security = next_domain; | ||
| 70 | return retval; | ||
| 71 | } | ||
| 72 | /* | 81 | /* |
| 73 | * Read permission is checked against interpreters using next domain. | 82 | * Read permission is checked against interpreters using next domain. |
| 74 | * '1' is the result of open_to_namei_flags(O_RDONLY). | 83 | * '1' is the result of open_to_namei_flags(O_RDONLY). |
| @@ -268,7 +277,9 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
| 268 | */ | 277 | */ |
| 269 | static struct security_operations tomoyo_security_ops = { | 278 | static struct security_operations tomoyo_security_ops = { |
| 270 | .name = "tomoyo", | 279 | .name = "tomoyo", |
| 280 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | ||
| 271 | .cred_prepare = tomoyo_cred_prepare, | 281 | .cred_prepare = tomoyo_cred_prepare, |
| 282 | .cred_transfer = tomoyo_cred_transfer, | ||
| 272 | .bprm_set_creds = tomoyo_bprm_set_creds, | 283 | .bprm_set_creds = tomoyo_bprm_set_creds, |
| 273 | .bprm_check_security = tomoyo_bprm_check_security, | 284 | .bprm_check_security = tomoyo_bprm_check_security, |
| 274 | #ifdef CONFIG_SYSCTL | 285 | #ifdef CONFIG_SYSCTL |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 0fd588a629cf..cd6ba0bf7069 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h | |||
| @@ -31,8 +31,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, | |||
| 31 | struct path *path2); | 31 | struct path *path2); |
| 32 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 32 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, |
| 33 | struct file *filp); | 33 | struct file *filp); |
| 34 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 34 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
| 35 | struct tomoyo_domain_info **next_domain); | ||
| 36 | 35 | ||
| 37 | /* Index numbers for Access Controls. */ | 36 | /* Index numbers for Access Controls. */ |
| 38 | 37 | ||
