diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/capability.c | 6 | ||||
-rw-r--r-- | security/commoncap.c | 25 | ||||
-rw-r--r-- | security/device_cgroup.c | 38 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 4 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 21 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 3 | ||||
-rw-r--r-- | security/keys/key.c | 6 | ||||
-rw-r--r-- | security/keys/keyctl.c | 15 | ||||
-rw-r--r-- | security/keys/keyring.c | 10 | ||||
-rw-r--r-- | security/keys/process_keys.c | 96 | ||||
-rw-r--r-- | security/keys/request_key.c | 21 | ||||
-rw-r--r-- | security/security.c | 10 | ||||
-rw-r--r-- | security/selinux/netnode.c | 3 | ||||
-rw-r--r-- | security/selinux/nlmsgtab.c | 5 | ||||
-rw-r--r-- | security/smack/Kconfig | 6 | ||||
-rw-r--r-- | security/smack/smackfs.c | 17 | ||||
-rw-r--r-- | security/yama/yama_lsm.c | 100 |
18 files changed, 258 insertions, 130 deletions
diff --git a/security/capability.c b/security/capability.c index b14a30c234b8..0fe5a026aef8 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name) | |||
395 | return 0; | 395 | return 0; |
396 | } | 396 | } |
397 | 397 | ||
398 | static int cap_kernel_module_from_file(struct file *file) | ||
399 | { | ||
400 | return 0; | ||
401 | } | ||
402 | |||
398 | static int cap_task_setpgid(struct task_struct *p, pid_t pgid) | 403 | static int cap_task_setpgid(struct task_struct *p, pid_t pgid) |
399 | { | 404 | { |
400 | return 0; | 405 | return 0; |
@@ -967,6 +972,7 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
967 | set_to_cap_if_null(ops, kernel_act_as); | 972 | set_to_cap_if_null(ops, kernel_act_as); |
968 | set_to_cap_if_null(ops, kernel_create_files_as); | 973 | set_to_cap_if_null(ops, kernel_create_files_as); |
969 | set_to_cap_if_null(ops, kernel_module_request); | 974 | set_to_cap_if_null(ops, kernel_module_request); |
975 | set_to_cap_if_null(ops, kernel_module_from_file); | ||
970 | set_to_cap_if_null(ops, task_fix_setuid); | 976 | set_to_cap_if_null(ops, task_fix_setuid); |
971 | set_to_cap_if_null(ops, task_setpgid); | 977 | set_to_cap_if_null(ops, task_setpgid); |
972 | set_to_cap_if_null(ops, task_getpgid); | 978 | set_to_cap_if_null(ops, task_getpgid); |
diff --git a/security/commoncap.c b/security/commoncap.c index 6dbae4650abe..7ee08c756d6b 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -76,24 +76,33 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | |||
76 | int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | 76 | int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, |
77 | int cap, int audit) | 77 | int cap, int audit) |
78 | { | 78 | { |
79 | for (;;) { | 79 | struct user_namespace *ns = targ_ns; |
80 | /* The owner of the user namespace has all caps. */ | ||
81 | if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid)) | ||
82 | return 0; | ||
83 | 80 | ||
81 | /* See if cred has the capability in the target user namespace | ||
82 | * by examining the target user namespace and all of the target | ||
83 | * user namespace's parents. | ||
84 | */ | ||
85 | for (;;) { | ||
84 | /* Do we have the necessary capabilities? */ | 86 | /* Do we have the necessary capabilities? */ |
85 | if (targ_ns == cred->user_ns) | 87 | if (ns == cred->user_ns) |
86 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; | 88 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; |
87 | 89 | ||
88 | /* Have we tried all of the parent namespaces? */ | 90 | /* Have we tried all of the parent namespaces? */ |
89 | if (targ_ns == &init_user_ns) | 91 | if (ns == &init_user_ns) |
90 | return -EPERM; | 92 | return -EPERM; |
91 | 93 | ||
94 | /* | ||
95 | * The owner of the user namespace in the parent of the | ||
96 | * user namespace has all caps. | ||
97 | */ | ||
98 | if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid)) | ||
99 | return 0; | ||
100 | |||
92 | /* | 101 | /* |
93 | *If you have a capability in a parent user ns, then you have | 102 | * If you have a capability in a parent user ns, then you have |
94 | * it over all children user namespaces as well. | 103 | * it over all children user namespaces as well. |
95 | */ | 104 | */ |
96 | targ_ns = targ_ns->parent; | 105 | ns = ns->parent; |
97 | } | 106 | } |
98 | 107 | ||
99 | /* We never get here */ | 108 | /* We never get here */ |
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 842c254396db..19ecc8de9e6b 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
@@ -82,6 +82,8 @@ static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig) | |||
82 | { | 82 | { |
83 | struct dev_exception_item *ex, *tmp, *new; | 83 | struct dev_exception_item *ex, *tmp, *new; |
84 | 84 | ||
85 | lockdep_assert_held(&devcgroup_mutex); | ||
86 | |||
85 | list_for_each_entry(ex, orig, list) { | 87 | list_for_each_entry(ex, orig, list) { |
86 | new = kmemdup(ex, sizeof(*ex), GFP_KERNEL); | 88 | new = kmemdup(ex, sizeof(*ex), GFP_KERNEL); |
87 | if (!new) | 89 | if (!new) |
@@ -107,6 +109,8 @@ static int dev_exception_add(struct dev_cgroup *dev_cgroup, | |||
107 | { | 109 | { |
108 | struct dev_exception_item *excopy, *walk; | 110 | struct dev_exception_item *excopy, *walk; |
109 | 111 | ||
112 | lockdep_assert_held(&devcgroup_mutex); | ||
113 | |||
110 | excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL); | 114 | excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL); |
111 | if (!excopy) | 115 | if (!excopy) |
112 | return -ENOMEM; | 116 | return -ENOMEM; |
@@ -137,6 +141,8 @@ static void dev_exception_rm(struct dev_cgroup *dev_cgroup, | |||
137 | { | 141 | { |
138 | struct dev_exception_item *walk, *tmp; | 142 | struct dev_exception_item *walk, *tmp; |
139 | 143 | ||
144 | lockdep_assert_held(&devcgroup_mutex); | ||
145 | |||
140 | list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) { | 146 | list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) { |
141 | if (walk->type != ex->type) | 147 | if (walk->type != ex->type) |
142 | continue; | 148 | continue; |
@@ -163,16 +169,18 @@ static void dev_exception_clean(struct dev_cgroup *dev_cgroup) | |||
163 | { | 169 | { |
164 | struct dev_exception_item *ex, *tmp; | 170 | struct dev_exception_item *ex, *tmp; |
165 | 171 | ||
172 | lockdep_assert_held(&devcgroup_mutex); | ||
173 | |||
166 | list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { | 174 | list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { |
167 | list_del(&ex->list); | 175 | list_del_rcu(&ex->list); |
168 | kfree(ex); | 176 | kfree_rcu(ex, rcu); |
169 | } | 177 | } |
170 | } | 178 | } |
171 | 179 | ||
172 | /* | 180 | /* |
173 | * called from kernel/cgroup.c with cgroup_lock() held. | 181 | * called from kernel/cgroup.c with cgroup_lock() held. |
174 | */ | 182 | */ |
175 | static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup) | 183 | static struct cgroup_subsys_state *devcgroup_css_alloc(struct cgroup *cgroup) |
176 | { | 184 | { |
177 | struct dev_cgroup *dev_cgroup, *parent_dev_cgroup; | 185 | struct dev_cgroup *dev_cgroup, *parent_dev_cgroup; |
178 | struct cgroup *parent_cgroup; | 186 | struct cgroup *parent_cgroup; |
@@ -202,7 +210,7 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup) | |||
202 | return &dev_cgroup->css; | 210 | return &dev_cgroup->css; |
203 | } | 211 | } |
204 | 212 | ||
205 | static void devcgroup_destroy(struct cgroup *cgroup) | 213 | static void devcgroup_css_free(struct cgroup *cgroup) |
206 | { | 214 | { |
207 | struct dev_cgroup *dev_cgroup; | 215 | struct dev_cgroup *dev_cgroup; |
208 | 216 | ||
@@ -298,7 +306,11 @@ static int may_access(struct dev_cgroup *dev_cgroup, | |||
298 | struct dev_exception_item *ex; | 306 | struct dev_exception_item *ex; |
299 | bool match = false; | 307 | bool match = false; |
300 | 308 | ||
301 | list_for_each_entry(ex, &dev_cgroup->exceptions, list) { | 309 | rcu_lockdep_assert(rcu_read_lock_held() || |
310 | lockdep_is_held(&devcgroup_mutex), | ||
311 | "device_cgroup::may_access() called without proper synchronization"); | ||
312 | |||
313 | list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) { | ||
302 | if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) | 314 | if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) |
303 | continue; | 315 | continue; |
304 | if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) | 316 | if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) |
@@ -352,6 +364,8 @@ static int parent_has_perm(struct dev_cgroup *childcg, | |||
352 | */ | 364 | */ |
353 | static inline int may_allow_all(struct dev_cgroup *parent) | 365 | static inline int may_allow_all(struct dev_cgroup *parent) |
354 | { | 366 | { |
367 | if (!parent) | ||
368 | return 1; | ||
355 | return parent->behavior == DEVCG_DEFAULT_ALLOW; | 369 | return parent->behavior == DEVCG_DEFAULT_ALLOW; |
356 | } | 370 | } |
357 | 371 | ||
@@ -376,11 +390,14 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
376 | int count, rc; | 390 | int count, rc; |
377 | struct dev_exception_item ex; | 391 | struct dev_exception_item ex; |
378 | struct cgroup *p = devcgroup->css.cgroup; | 392 | struct cgroup *p = devcgroup->css.cgroup; |
379 | struct dev_cgroup *parent = cgroup_to_devcgroup(p->parent); | 393 | struct dev_cgroup *parent = NULL; |
380 | 394 | ||
381 | if (!capable(CAP_SYS_ADMIN)) | 395 | if (!capable(CAP_SYS_ADMIN)) |
382 | return -EPERM; | 396 | return -EPERM; |
383 | 397 | ||
398 | if (p->parent) | ||
399 | parent = cgroup_to_devcgroup(p->parent); | ||
400 | |||
384 | memset(&ex, 0, sizeof(ex)); | 401 | memset(&ex, 0, sizeof(ex)); |
385 | b = buffer; | 402 | b = buffer; |
386 | 403 | ||
@@ -391,11 +408,14 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
391 | if (!may_allow_all(parent)) | 408 | if (!may_allow_all(parent)) |
392 | return -EPERM; | 409 | return -EPERM; |
393 | dev_exception_clean(devcgroup); | 410 | dev_exception_clean(devcgroup); |
411 | devcgroup->behavior = DEVCG_DEFAULT_ALLOW; | ||
412 | if (!parent) | ||
413 | break; | ||
414 | |||
394 | rc = dev_exceptions_copy(&devcgroup->exceptions, | 415 | rc = dev_exceptions_copy(&devcgroup->exceptions, |
395 | &parent->exceptions); | 416 | &parent->exceptions); |
396 | if (rc) | 417 | if (rc) |
397 | return rc; | 418 | return rc; |
398 | devcgroup->behavior = DEVCG_DEFAULT_ALLOW; | ||
399 | break; | 419 | break; |
400 | case DEVCG_DENY: | 420 | case DEVCG_DENY: |
401 | dev_exception_clean(devcgroup); | 421 | dev_exception_clean(devcgroup); |
@@ -544,8 +564,8 @@ static struct cftype dev_cgroup_files[] = { | |||
544 | struct cgroup_subsys devices_subsys = { | 564 | struct cgroup_subsys devices_subsys = { |
545 | .name = "devices", | 565 | .name = "devices", |
546 | .can_attach = devcgroup_can_attach, | 566 | .can_attach = devcgroup_can_attach, |
547 | .create = devcgroup_create, | 567 | .css_alloc = devcgroup_css_alloc, |
548 | .destroy = devcgroup_destroy, | 568 | .css_free = devcgroup_css_free, |
549 | .subsys_id = devices_subsys_id, | 569 | .subsys_id = devices_subsys_id, |
550 | .base_cftypes = dev_cgroup_files, | 570 | .base_cftypes = dev_cgroup_files, |
551 | 571 | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 6ee8826662cc..3b2adb794f15 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); | |||
127 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 127 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
128 | 128 | ||
129 | /* IMA policy related functions */ | 129 | /* IMA policy related functions */ |
130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; | 130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR }; |
131 | 131 | ||
132 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | 132 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
133 | int flags); | 133 | int flags); |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index b356884fb3ef..0cea3db21657 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -100,12 +100,12 @@ err_out: | |||
100 | * ima_get_action - appraise & measure decision based on policy. | 100 | * ima_get_action - appraise & measure decision based on policy. |
101 | * @inode: pointer to inode to measure | 101 | * @inode: pointer to inode to measure |
102 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | 102 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) |
103 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) | 103 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP, MODULE_CHECK) |
104 | * | 104 | * |
105 | * The policy is defined in terms of keypairs: | 105 | * The policy is defined in terms of keypairs: |
106 | * subj=, obj=, type=, func=, mask=, fsmagic= | 106 | * subj=, obj=, type=, func=, mask=, fsmagic= |
107 | * subj,obj, and type: are LSM specific. | 107 | * subj,obj, and type: are LSM specific. |
108 | * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP | 108 | * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP | MODULE_CHECK |
109 | * mask: contains the permission mask | 109 | * mask: contains the permission mask |
110 | * fsmagic: hex value | 110 | * fsmagic: hex value |
111 | * | 111 | * |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 73c9a268253e..45de18e9a6f2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -280,6 +280,27 @@ int ima_file_check(struct file *file, int mask) | |||
280 | } | 280 | } |
281 | EXPORT_SYMBOL_GPL(ima_file_check); | 281 | EXPORT_SYMBOL_GPL(ima_file_check); |
282 | 282 | ||
283 | /** | ||
284 | * ima_module_check - based on policy, collect/store/appraise measurement. | ||
285 | * @file: pointer to the file to be measured/appraised | ||
286 | * | ||
287 | * Measure/appraise kernel modules based on policy. | ||
288 | * | ||
289 | * Always return 0 and audit dentry_open failures. | ||
290 | * Return code is based upon measurement appraisal. | ||
291 | */ | ||
292 | int ima_module_check(struct file *file) | ||
293 | { | ||
294 | int rc; | ||
295 | |||
296 | if (!file) | ||
297 | rc = INTEGRITY_UNKNOWN; | ||
298 | else | ||
299 | rc = process_measurement(file, file->f_dentry->d_name.name, | ||
300 | MAY_EXEC, MODULE_CHECK); | ||
301 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; | ||
302 | } | ||
303 | |||
283 | static int __init init_ima(void) | 304 | static int __init init_ima(void) |
284 | { | 305 | { |
285 | int error; | 306 | int error; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index c7dacd2eab7a..af7d182d5a46 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -80,6 +80,7 @@ static struct ima_rule_entry default_rules[] = { | |||
80 | .flags = IMA_FUNC | IMA_MASK}, | 80 | .flags = IMA_FUNC | IMA_MASK}, |
81 | {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, | 81 | {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, |
82 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 82 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
83 | {.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC}, | ||
83 | }; | 84 | }; |
84 | 85 | ||
85 | static struct ima_rule_entry default_appraise_rules[] = { | 86 | static struct ima_rule_entry default_appraise_rules[] = { |
@@ -401,6 +402,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
401 | /* PATH_CHECK is for backwards compat */ | 402 | /* PATH_CHECK is for backwards compat */ |
402 | else if (strcmp(args[0].from, "PATH_CHECK") == 0) | 403 | else if (strcmp(args[0].from, "PATH_CHECK") == 0) |
403 | entry->func = FILE_CHECK; | 404 | entry->func = FILE_CHECK; |
405 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) | ||
406 | entry->func = MODULE_CHECK; | ||
404 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) | 407 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) |
405 | entry->func = FILE_MMAP; | 408 | entry->func = FILE_MMAP; |
406 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) | 409 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) |
diff --git a/security/keys/key.c b/security/keys/key.c index a15c9da8f971..8fb7c7bd4657 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -854,13 +854,13 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
854 | /* if the client doesn't provide, decide on the permissions we want */ | 854 | /* if the client doesn't provide, decide on the permissions we want */ |
855 | if (perm == KEY_PERM_UNDEF) { | 855 | if (perm == KEY_PERM_UNDEF) { |
856 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; | 856 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; |
857 | perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; | 857 | perm |= KEY_USR_VIEW; |
858 | 858 | ||
859 | if (ktype->read) | 859 | if (ktype->read) |
860 | perm |= KEY_POS_READ | KEY_USR_READ; | 860 | perm |= KEY_POS_READ; |
861 | 861 | ||
862 | if (ktype == &key_type_keyring || ktype->update) | 862 | if (ktype == &key_type_keyring || ktype->update) |
863 | perm |= KEY_USR_WRITE; | 863 | perm |= KEY_POS_WRITE; |
864 | } | 864 | } |
865 | 865 | ||
866 | /* allocate a new key */ | 866 | /* allocate a new key */ |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 5d34b4e827d6..4b5c948eb414 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1132,12 +1132,12 @@ long keyctl_instantiate_key_iov(key_serial_t id, | |||
1132 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, | 1132 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, |
1133 | ARRAY_SIZE(iovstack), iovstack, &iov); | 1133 | ARRAY_SIZE(iovstack), iovstack, &iov); |
1134 | if (ret < 0) | 1134 | if (ret < 0) |
1135 | return ret; | 1135 | goto err; |
1136 | if (ret == 0) | 1136 | if (ret == 0) |
1137 | goto no_payload_free; | 1137 | goto no_payload_free; |
1138 | 1138 | ||
1139 | ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); | 1139 | ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); |
1140 | 1140 | err: | |
1141 | if (iov != iovstack) | 1141 | if (iov != iovstack) |
1142 | kfree(iov); | 1142 | kfree(iov); |
1143 | return ret; | 1143 | return ret; |
@@ -1495,7 +1495,8 @@ long keyctl_session_to_parent(void) | |||
1495 | goto error_keyring; | 1495 | goto error_keyring; |
1496 | newwork = &cred->rcu; | 1496 | newwork = &cred->rcu; |
1497 | 1497 | ||
1498 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | 1498 | cred->session_keyring = key_ref_to_ptr(keyring_r); |
1499 | keyring_r = NULL; | ||
1499 | init_task_work(newwork, key_change_session_keyring); | 1500 | init_task_work(newwork, key_change_session_keyring); |
1500 | 1501 | ||
1501 | me = current; | 1502 | me = current; |
@@ -1519,7 +1520,7 @@ long keyctl_session_to_parent(void) | |||
1519 | mycred = current_cred(); | 1520 | mycred = current_cred(); |
1520 | pcred = __task_cred(parent); | 1521 | pcred = __task_cred(parent); |
1521 | if (mycred == pcred || | 1522 | if (mycred == pcred || |
1522 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { | 1523 | mycred->session_keyring == pcred->session_keyring) { |
1523 | ret = 0; | 1524 | ret = 0; |
1524 | goto unlock; | 1525 | goto unlock; |
1525 | } | 1526 | } |
@@ -1535,9 +1536,9 @@ long keyctl_session_to_parent(void) | |||
1535 | goto unlock; | 1536 | goto unlock; |
1536 | 1537 | ||
1537 | /* the keyrings must have the same UID */ | 1538 | /* the keyrings must have the same UID */ |
1538 | if ((pcred->tgcred->session_keyring && | 1539 | if ((pcred->session_keyring && |
1539 | !uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) || | 1540 | !uid_eq(pcred->session_keyring->uid, mycred->euid)) || |
1540 | !uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid)) | 1541 | !uid_eq(mycred->session_keyring->uid, mycred->euid)) |
1541 | goto unlock; | 1542 | goto unlock; |
1542 | 1543 | ||
1543 | /* cancel an already pending keyring replacement */ | 1544 | /* cancel an already pending keyring replacement */ |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 6e42df15a24c..6ece7f2e5707 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -257,17 +257,14 @@ error: | |||
257 | * Allocate a keyring and link into the destination keyring. | 257 | * Allocate a keyring and link into the destination keyring. |
258 | */ | 258 | */ |
259 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | 259 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, |
260 | const struct cred *cred, unsigned long flags, | 260 | const struct cred *cred, key_perm_t perm, |
261 | struct key *dest) | 261 | unsigned long flags, struct key *dest) |
262 | { | 262 | { |
263 | struct key *keyring; | 263 | struct key *keyring; |
264 | int ret; | 264 | int ret; |
265 | 265 | ||
266 | keyring = key_alloc(&key_type_keyring, description, | 266 | keyring = key_alloc(&key_type_keyring, description, |
267 | uid, gid, cred, | 267 | uid, gid, cred, perm, flags); |
268 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
269 | flags); | ||
270 | |||
271 | if (!IS_ERR(keyring)) { | 268 | if (!IS_ERR(keyring)) { |
272 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); | 269 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); |
273 | if (ret < 0) { | 270 | if (ret < 0) { |
@@ -278,6 +275,7 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | |||
278 | 275 | ||
279 | return keyring; | 276 | return keyring; |
280 | } | 277 | } |
278 | EXPORT_SYMBOL(keyring_alloc); | ||
281 | 279 | ||
282 | /** | 280 | /** |
283 | * keyring_search_aux - Search a keyring tree for a key matching some criteria | 281 | * keyring_search_aux - Search a keyring tree for a key matching some criteria |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index a58f712605d8..20e4bf57aec8 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -45,10 +45,12 @@ int install_user_keyrings(void) | |||
45 | struct user_struct *user; | 45 | struct user_struct *user; |
46 | const struct cred *cred; | 46 | const struct cred *cred; |
47 | struct key *uid_keyring, *session_keyring; | 47 | struct key *uid_keyring, *session_keyring; |
48 | key_perm_t user_keyring_perm; | ||
48 | char buf[20]; | 49 | char buf[20]; |
49 | int ret; | 50 | int ret; |
50 | uid_t uid; | 51 | uid_t uid; |
51 | 52 | ||
53 | user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; | ||
52 | cred = current_cred(); | 54 | cred = current_cred(); |
53 | user = cred->user; | 55 | user = cred->user; |
54 | uid = from_kuid(cred->user_ns, user->uid); | 56 | uid = from_kuid(cred->user_ns, user->uid); |
@@ -73,8 +75,8 @@ int install_user_keyrings(void) | |||
73 | uid_keyring = find_keyring_by_name(buf, true); | 75 | uid_keyring = find_keyring_by_name(buf, true); |
74 | if (IS_ERR(uid_keyring)) { | 76 | if (IS_ERR(uid_keyring)) { |
75 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, | 77 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, |
76 | cred, KEY_ALLOC_IN_QUOTA, | 78 | cred, user_keyring_perm, |
77 | NULL); | 79 | KEY_ALLOC_IN_QUOTA, NULL); |
78 | if (IS_ERR(uid_keyring)) { | 80 | if (IS_ERR(uid_keyring)) { |
79 | ret = PTR_ERR(uid_keyring); | 81 | ret = PTR_ERR(uid_keyring); |
80 | goto error; | 82 | goto error; |
@@ -89,7 +91,8 @@ int install_user_keyrings(void) | |||
89 | if (IS_ERR(session_keyring)) { | 91 | if (IS_ERR(session_keyring)) { |
90 | session_keyring = | 92 | session_keyring = |
91 | keyring_alloc(buf, user->uid, INVALID_GID, | 93 | keyring_alloc(buf, user->uid, INVALID_GID, |
92 | cred, KEY_ALLOC_IN_QUOTA, NULL); | 94 | cred, user_keyring_perm, |
95 | KEY_ALLOC_IN_QUOTA, NULL); | ||
93 | if (IS_ERR(session_keyring)) { | 96 | if (IS_ERR(session_keyring)) { |
94 | ret = PTR_ERR(session_keyring); | 97 | ret = PTR_ERR(session_keyring); |
95 | goto error_release; | 98 | goto error_release; |
@@ -130,6 +133,7 @@ int install_thread_keyring_to_cred(struct cred *new) | |||
130 | struct key *keyring; | 133 | struct key *keyring; |
131 | 134 | ||
132 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, | 135 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
136 | KEY_POS_ALL | KEY_USR_VIEW, | ||
133 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 137 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
134 | if (IS_ERR(keyring)) | 138 | if (IS_ERR(keyring)) |
135 | return PTR_ERR(keyring); | 139 | return PTR_ERR(keyring); |
@@ -170,27 +174,18 @@ static int install_thread_keyring(void) | |||
170 | int install_process_keyring_to_cred(struct cred *new) | 174 | int install_process_keyring_to_cred(struct cred *new) |
171 | { | 175 | { |
172 | struct key *keyring; | 176 | struct key *keyring; |
173 | int ret; | ||
174 | 177 | ||
175 | if (new->tgcred->process_keyring) | 178 | if (new->process_keyring) |
176 | return -EEXIST; | 179 | return -EEXIST; |
177 | 180 | ||
178 | keyring = keyring_alloc("_pid", new->uid, new->gid, | 181 | keyring = keyring_alloc("_pid", new->uid, new->gid, new, |
179 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); | 182 | KEY_POS_ALL | KEY_USR_VIEW, |
183 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
180 | if (IS_ERR(keyring)) | 184 | if (IS_ERR(keyring)) |
181 | return PTR_ERR(keyring); | 185 | return PTR_ERR(keyring); |
182 | 186 | ||
183 | spin_lock_irq(&new->tgcred->lock); | 187 | new->process_keyring = keyring; |
184 | if (!new->tgcred->process_keyring) { | 188 | return 0; |
185 | new->tgcred->process_keyring = keyring; | ||
186 | keyring = NULL; | ||
187 | ret = 0; | ||
188 | } else { | ||
189 | ret = -EEXIST; | ||
190 | } | ||
191 | spin_unlock_irq(&new->tgcred->lock); | ||
192 | key_put(keyring); | ||
193 | return ret; | ||
194 | } | 189 | } |
195 | 190 | ||
196 | /* | 191 | /* |
@@ -231,11 +226,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
231 | /* create an empty session keyring */ | 226 | /* create an empty session keyring */ |
232 | if (!keyring) { | 227 | if (!keyring) { |
233 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 228 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
234 | if (cred->tgcred->session_keyring) | 229 | if (cred->session_keyring) |
235 | flags = KEY_ALLOC_IN_QUOTA; | 230 | flags = KEY_ALLOC_IN_QUOTA; |
236 | 231 | ||
237 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, | 232 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, |
238 | cred, flags, NULL); | 233 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, |
234 | flags, NULL); | ||
239 | if (IS_ERR(keyring)) | 235 | if (IS_ERR(keyring)) |
240 | return PTR_ERR(keyring); | 236 | return PTR_ERR(keyring); |
241 | } else { | 237 | } else { |
@@ -243,17 +239,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
243 | } | 239 | } |
244 | 240 | ||
245 | /* install the keyring */ | 241 | /* install the keyring */ |
246 | spin_lock_irq(&cred->tgcred->lock); | 242 | old = cred->session_keyring; |
247 | old = cred->tgcred->session_keyring; | 243 | rcu_assign_pointer(cred->session_keyring, keyring); |
248 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); | 244 | |
249 | spin_unlock_irq(&cred->tgcred->lock); | 245 | if (old) |
250 | |||
251 | /* we're using RCU on the pointer, but there's no point synchronising | ||
252 | * on it if it didn't previously point to anything */ | ||
253 | if (old) { | ||
254 | synchronize_rcu(); | ||
255 | key_put(old); | 246 | key_put(old); |
256 | } | ||
257 | 247 | ||
258 | return 0; | 248 | return 0; |
259 | } | 249 | } |
@@ -358,8 +348,6 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
358 | 348 | ||
359 | switch (PTR_ERR(key_ref)) { | 349 | switch (PTR_ERR(key_ref)) { |
360 | case -EAGAIN: /* no key */ | 350 | case -EAGAIN: /* no key */ |
361 | if (ret) | ||
362 | break; | ||
363 | case -ENOKEY: /* negative key */ | 351 | case -ENOKEY: /* negative key */ |
364 | ret = key_ref; | 352 | ret = key_ref; |
365 | break; | 353 | break; |
@@ -370,17 +358,15 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
370 | } | 358 | } |
371 | 359 | ||
372 | /* search the process keyring second */ | 360 | /* search the process keyring second */ |
373 | if (cred->tgcred->process_keyring) { | 361 | if (cred->process_keyring) { |
374 | key_ref = keyring_search_aux( | 362 | key_ref = keyring_search_aux( |
375 | make_key_ref(cred->tgcred->process_keyring, 1), | 363 | make_key_ref(cred->process_keyring, 1), |
376 | cred, type, description, match, no_state_check); | 364 | cred, type, description, match, no_state_check); |
377 | if (!IS_ERR(key_ref)) | 365 | if (!IS_ERR(key_ref)) |
378 | goto found; | 366 | goto found; |
379 | 367 | ||
380 | switch (PTR_ERR(key_ref)) { | 368 | switch (PTR_ERR(key_ref)) { |
381 | case -EAGAIN: /* no key */ | 369 | case -EAGAIN: /* no key */ |
382 | if (ret) | ||
383 | break; | ||
384 | case -ENOKEY: /* negative key */ | 370 | case -ENOKEY: /* negative key */ |
385 | ret = key_ref; | 371 | ret = key_ref; |
386 | break; | 372 | break; |
@@ -391,12 +377,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
391 | } | 377 | } |
392 | 378 | ||
393 | /* search the session keyring */ | 379 | /* search the session keyring */ |
394 | if (cred->tgcred->session_keyring) { | 380 | if (cred->session_keyring) { |
395 | rcu_read_lock(); | 381 | rcu_read_lock(); |
396 | key_ref = keyring_search_aux( | 382 | key_ref = keyring_search_aux( |
397 | make_key_ref(rcu_dereference( | 383 | make_key_ref(rcu_dereference(cred->session_keyring), 1), |
398 | cred->tgcred->session_keyring), | ||
399 | 1), | ||
400 | cred, type, description, match, no_state_check); | 384 | cred, type, description, match, no_state_check); |
401 | rcu_read_unlock(); | 385 | rcu_read_unlock(); |
402 | 386 | ||
@@ -566,7 +550,7 @@ try_again: | |||
566 | break; | 550 | break; |
567 | 551 | ||
568 | case KEY_SPEC_PROCESS_KEYRING: | 552 | case KEY_SPEC_PROCESS_KEYRING: |
569 | if (!cred->tgcred->process_keyring) { | 553 | if (!cred->process_keyring) { |
570 | if (!(lflags & KEY_LOOKUP_CREATE)) | 554 | if (!(lflags & KEY_LOOKUP_CREATE)) |
571 | goto error; | 555 | goto error; |
572 | 556 | ||
@@ -578,13 +562,13 @@ try_again: | |||
578 | goto reget_creds; | 562 | goto reget_creds; |
579 | } | 563 | } |
580 | 564 | ||
581 | key = cred->tgcred->process_keyring; | 565 | key = cred->process_keyring; |
582 | atomic_inc(&key->usage); | 566 | atomic_inc(&key->usage); |
583 | key_ref = make_key_ref(key, 1); | 567 | key_ref = make_key_ref(key, 1); |
584 | break; | 568 | break; |
585 | 569 | ||
586 | case KEY_SPEC_SESSION_KEYRING: | 570 | case KEY_SPEC_SESSION_KEYRING: |
587 | if (!cred->tgcred->session_keyring) { | 571 | if (!cred->session_keyring) { |
588 | /* always install a session keyring upon access if one | 572 | /* always install a session keyring upon access if one |
589 | * doesn't exist yet */ | 573 | * doesn't exist yet */ |
590 | ret = install_user_keyrings(); | 574 | ret = install_user_keyrings(); |
@@ -599,7 +583,7 @@ try_again: | |||
599 | if (ret < 0) | 583 | if (ret < 0) |
600 | goto error; | 584 | goto error; |
601 | goto reget_creds; | 585 | goto reget_creds; |
602 | } else if (cred->tgcred->session_keyring == | 586 | } else if (cred->session_keyring == |
603 | cred->user->session_keyring && | 587 | cred->user->session_keyring && |
604 | lflags & KEY_LOOKUP_CREATE) { | 588 | lflags & KEY_LOOKUP_CREATE) { |
605 | ret = join_session_keyring(NULL); | 589 | ret = join_session_keyring(NULL); |
@@ -609,7 +593,7 @@ try_again: | |||
609 | } | 593 | } |
610 | 594 | ||
611 | rcu_read_lock(); | 595 | rcu_read_lock(); |
612 | key = rcu_dereference(cred->tgcred->session_keyring); | 596 | key = rcu_dereference(cred->session_keyring); |
613 | atomic_inc(&key->usage); | 597 | atomic_inc(&key->usage); |
614 | rcu_read_unlock(); | 598 | rcu_read_unlock(); |
615 | key_ref = make_key_ref(key, 1); | 599 | key_ref = make_key_ref(key, 1); |
@@ -769,12 +753,6 @@ long join_session_keyring(const char *name) | |||
769 | struct key *keyring; | 753 | struct key *keyring; |
770 | long ret, serial; | 754 | long ret, serial; |
771 | 755 | ||
772 | /* only permit this if there's a single thread in the thread group - | ||
773 | * this avoids us having to adjust the creds on all threads and risking | ||
774 | * ENOMEM */ | ||
775 | if (!current_is_single_threaded()) | ||
776 | return -EMLINK; | ||
777 | |||
778 | new = prepare_creds(); | 756 | new = prepare_creds(); |
779 | if (!new) | 757 | if (!new) |
780 | return -ENOMEM; | 758 | return -ENOMEM; |
@@ -786,7 +764,7 @@ long join_session_keyring(const char *name) | |||
786 | if (ret < 0) | 764 | if (ret < 0) |
787 | goto error; | 765 | goto error; |
788 | 766 | ||
789 | serial = new->tgcred->session_keyring->serial; | 767 | serial = new->session_keyring->serial; |
790 | ret = commit_creds(new); | 768 | ret = commit_creds(new); |
791 | if (ret == 0) | 769 | if (ret == 0) |
792 | ret = serial; | 770 | ret = serial; |
@@ -800,8 +778,10 @@ long join_session_keyring(const char *name) | |||
800 | keyring = find_keyring_by_name(name, false); | 778 | keyring = find_keyring_by_name(name, false); |
801 | if (PTR_ERR(keyring) == -ENOKEY) { | 779 | if (PTR_ERR(keyring) == -ENOKEY) { |
802 | /* not found - try and create a new one */ | 780 | /* not found - try and create a new one */ |
803 | keyring = keyring_alloc(name, old->uid, old->gid, old, | 781 | keyring = keyring_alloc( |
804 | KEY_ALLOC_IN_QUOTA, NULL); | 782 | name, old->uid, old->gid, old, |
783 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, | ||
784 | KEY_ALLOC_IN_QUOTA, NULL); | ||
805 | if (IS_ERR(keyring)) { | 785 | if (IS_ERR(keyring)) { |
806 | ret = PTR_ERR(keyring); | 786 | ret = PTR_ERR(keyring); |
807 | goto error2; | 787 | goto error2; |
@@ -809,6 +789,9 @@ long join_session_keyring(const char *name) | |||
809 | } else if (IS_ERR(keyring)) { | 789 | } else if (IS_ERR(keyring)) { |
810 | ret = PTR_ERR(keyring); | 790 | ret = PTR_ERR(keyring); |
811 | goto error2; | 791 | goto error2; |
792 | } else if (keyring == new->session_keyring) { | ||
793 | ret = 0; | ||
794 | goto error2; | ||
812 | } | 795 | } |
813 | 796 | ||
814 | /* we've got a keyring - now to install it */ | 797 | /* we've got a keyring - now to install it */ |
@@ -865,8 +848,7 @@ void key_change_session_keyring(struct callback_head *twork) | |||
865 | 848 | ||
866 | new->jit_keyring = old->jit_keyring; | 849 | new->jit_keyring = old->jit_keyring; |
867 | new->thread_keyring = key_get(old->thread_keyring); | 850 | new->thread_keyring = key_get(old->thread_keyring); |
868 | new->tgcred->tgid = old->tgcred->tgid; | 851 | new->process_keyring = key_get(old->process_keyring); |
869 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
870 | 852 | ||
871 | security_transfer_creds(new, old); | 853 | security_transfer_creds(new, old); |
872 | 854 | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 66e21184b559..4bd6bdb74193 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -126,6 +126,7 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
126 | 126 | ||
127 | cred = get_current_cred(); | 127 | cred = get_current_cred(); |
128 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, | 128 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, |
129 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, | ||
129 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 130 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
130 | put_cred(cred); | 131 | put_cred(cred); |
131 | if (IS_ERR(keyring)) { | 132 | if (IS_ERR(keyring)) { |
@@ -150,12 +151,12 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
150 | cred->thread_keyring ? cred->thread_keyring->serial : 0); | 151 | cred->thread_keyring ? cred->thread_keyring->serial : 0); |
151 | 152 | ||
152 | prkey = 0; | 153 | prkey = 0; |
153 | if (cred->tgcred->process_keyring) | 154 | if (cred->process_keyring) |
154 | prkey = cred->tgcred->process_keyring->serial; | 155 | prkey = cred->process_keyring->serial; |
155 | sprintf(keyring_str[1], "%d", prkey); | 156 | sprintf(keyring_str[1], "%d", prkey); |
156 | 157 | ||
157 | rcu_read_lock(); | 158 | rcu_read_lock(); |
158 | session = rcu_dereference(cred->tgcred->session_keyring); | 159 | session = rcu_dereference(cred->session_keyring); |
159 | if (!session) | 160 | if (!session) |
160 | session = cred->user->session_keyring; | 161 | session = cred->user->session_keyring; |
161 | sskey = session->serial; | 162 | sskey = session->serial; |
@@ -297,14 +298,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
297 | break; | 298 | break; |
298 | 299 | ||
299 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | 300 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
300 | dest_keyring = key_get(cred->tgcred->process_keyring); | 301 | dest_keyring = key_get(cred->process_keyring); |
301 | if (dest_keyring) | 302 | if (dest_keyring) |
302 | break; | 303 | break; |
303 | 304 | ||
304 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | 305 | case KEY_REQKEY_DEFL_SESSION_KEYRING: |
305 | rcu_read_lock(); | 306 | rcu_read_lock(); |
306 | dest_keyring = key_get( | 307 | dest_keyring = key_get( |
307 | rcu_dereference(cred->tgcred->session_keyring)); | 308 | rcu_dereference(cred->session_keyring)); |
308 | rcu_read_unlock(); | 309 | rcu_read_unlock(); |
309 | 310 | ||
310 | if (dest_keyring) | 311 | if (dest_keyring) |
@@ -347,6 +348,7 @@ static int construct_alloc_key(struct key_type *type, | |||
347 | const struct cred *cred = current_cred(); | 348 | const struct cred *cred = current_cred(); |
348 | unsigned long prealloc; | 349 | unsigned long prealloc; |
349 | struct key *key; | 350 | struct key *key; |
351 | key_perm_t perm; | ||
350 | key_ref_t key_ref; | 352 | key_ref_t key_ref; |
351 | int ret; | 353 | int ret; |
352 | 354 | ||
@@ -355,8 +357,15 @@ static int construct_alloc_key(struct key_type *type, | |||
355 | *_key = NULL; | 357 | *_key = NULL; |
356 | mutex_lock(&user->cons_lock); | 358 | mutex_lock(&user->cons_lock); |
357 | 359 | ||
360 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; | ||
361 | perm |= KEY_USR_VIEW; | ||
362 | if (type->read) | ||
363 | perm |= KEY_POS_READ; | ||
364 | if (type == &key_type_keyring || type->update) | ||
365 | perm |= KEY_POS_WRITE; | ||
366 | |||
358 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, | 367 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, |
359 | KEY_POS_ALL, flags); | 368 | perm, flags); |
360 | if (IS_ERR(key)) | 369 | if (IS_ERR(key)) |
361 | goto alloc_failed; | 370 | goto alloc_failed; |
362 | 371 | ||
diff --git a/security/security.c b/security/security.c index 8dcd4ae10a5f..daa97f4ac9d1 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -820,6 +820,16 @@ int security_kernel_module_request(char *kmod_name) | |||
820 | return security_ops->kernel_module_request(kmod_name); | 820 | return security_ops->kernel_module_request(kmod_name); |
821 | } | 821 | } |
822 | 822 | ||
823 | int security_kernel_module_from_file(struct file *file) | ||
824 | { | ||
825 | int ret; | ||
826 | |||
827 | ret = security_ops->kernel_module_from_file(file); | ||
828 | if (ret) | ||
829 | return ret; | ||
830 | return ima_module_check(file); | ||
831 | } | ||
832 | |||
823 | int security_task_fix_setuid(struct cred *new, const struct cred *old, | 833 | int security_task_fix_setuid(struct cred *new, const struct cred *old, |
824 | int flags) | 834 | int flags) |
825 | { | 835 | { |
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 28f911cdd7c7..c5454c0477c3 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -174,7 +174,8 @@ static void sel_netnode_insert(struct sel_netnode *node) | |||
174 | if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) { | 174 | if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) { |
175 | struct sel_netnode *tail; | 175 | struct sel_netnode *tail; |
176 | tail = list_entry( | 176 | tail = list_entry( |
177 | rcu_dereference(sel_netnode_hash[idx].list.prev), | 177 | rcu_dereference_protected(sel_netnode_hash[idx].list.prev, |
178 | lockdep_is_held(&sel_netnode_lock)), | ||
178 | struct sel_netnode, list); | 179 | struct sel_netnode, list); |
179 | list_del_rcu(&tail->list); | 180 | list_del_rcu(&tail->list); |
180 | kfree_rcu(tail, rcu); | 181 | kfree_rcu(tail, rcu); |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index d309e7f472d8..855e464e92ef 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
@@ -67,6 +67,11 @@ static struct nlmsg_perm nlmsg_route_perms[] = | |||
67 | { RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 67 | { RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
68 | { RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 68 | { RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
69 | { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | 69 | { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, |
70 | { RTM_NEWNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | ||
71 | { RTM_GETNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | ||
72 | { RTM_NEWMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | ||
73 | { RTM_DELMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | ||
74 | { RTM_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | ||
70 | }; | 75 | }; |
71 | 76 | ||
72 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | 77 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = |
diff --git a/security/smack/Kconfig b/security/smack/Kconfig index 603b08784341..e69de9c642b7 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig | |||
@@ -1,6 +1,10 @@ | |||
1 | config SECURITY_SMACK | 1 | config SECURITY_SMACK |
2 | bool "Simplified Mandatory Access Control Kernel Support" | 2 | bool "Simplified Mandatory Access Control Kernel Support" |
3 | depends on NETLABEL && SECURITY_NETWORK | 3 | depends on NET |
4 | depends on INET | ||
5 | depends on SECURITY | ||
6 | select NETLABEL | ||
7 | select SECURITY_NETWORK | ||
4 | default n | 8 | default n |
5 | help | 9 | help |
6 | This selects the Simplified Mandatory Access Control Kernel. | 10 | This selects the Simplified Mandatory Access Control Kernel. |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 99929a50093a..76a5dca46404 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -2063,6 +2063,19 @@ static const struct file_operations smk_revoke_subj_ops = { | |||
2063 | .llseek = generic_file_llseek, | 2063 | .llseek = generic_file_llseek, |
2064 | }; | 2064 | }; |
2065 | 2065 | ||
2066 | static struct kset *smackfs_kset; | ||
2067 | /** | ||
2068 | * smk_init_sysfs - initialize /sys/fs/smackfs | ||
2069 | * | ||
2070 | */ | ||
2071 | static int smk_init_sysfs(void) | ||
2072 | { | ||
2073 | smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj); | ||
2074 | if (!smackfs_kset) | ||
2075 | return -ENOMEM; | ||
2076 | return 0; | ||
2077 | } | ||
2078 | |||
2066 | /** | 2079 | /** |
2067 | * smk_fill_super - fill the /smackfs superblock | 2080 | * smk_fill_super - fill the /smackfs superblock |
2068 | * @sb: the empty superblock | 2081 | * @sb: the empty superblock |
@@ -2183,6 +2196,10 @@ static int __init init_smk_fs(void) | |||
2183 | if (!security_module_enable(&smack_ops)) | 2196 | if (!security_module_enable(&smack_ops)) |
2184 | return 0; | 2197 | return 0; |
2185 | 2198 | ||
2199 | err = smk_init_sysfs(); | ||
2200 | if (err) | ||
2201 | printk(KERN_ERR "smackfs: sysfs mountpoint problem.\n"); | ||
2202 | |||
2186 | err = register_filesystem(&smk_fs_type); | 2203 | err = register_filesystem(&smk_fs_type); |
2187 | if (!err) { | 2204 | if (!err) { |
2188 | smackfs_mount = kern_mount(&smk_fs_type); | 2205 | smackfs_mount = kern_mount(&smk_fs_type); |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index b4c29848b49d..23414b93771f 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/prctl.h> | 18 | #include <linux/prctl.h> |
19 | #include <linux/ratelimit.h> | 19 | #include <linux/ratelimit.h> |
20 | #include <linux/workqueue.h> | ||
20 | 21 | ||
21 | #define YAMA_SCOPE_DISABLED 0 | 22 | #define YAMA_SCOPE_DISABLED 0 |
22 | #define YAMA_SCOPE_RELATIONAL 1 | 23 | #define YAMA_SCOPE_RELATIONAL 1 |
@@ -29,12 +30,37 @@ static int ptrace_scope = YAMA_SCOPE_RELATIONAL; | |||
29 | struct ptrace_relation { | 30 | struct ptrace_relation { |
30 | struct task_struct *tracer; | 31 | struct task_struct *tracer; |
31 | struct task_struct *tracee; | 32 | struct task_struct *tracee; |
33 | bool invalid; | ||
32 | struct list_head node; | 34 | struct list_head node; |
35 | struct rcu_head rcu; | ||
33 | }; | 36 | }; |
34 | 37 | ||
35 | static LIST_HEAD(ptracer_relations); | 38 | static LIST_HEAD(ptracer_relations); |
36 | static DEFINE_SPINLOCK(ptracer_relations_lock); | 39 | static DEFINE_SPINLOCK(ptracer_relations_lock); |
37 | 40 | ||
41 | static void yama_relation_cleanup(struct work_struct *work); | ||
42 | static DECLARE_WORK(yama_relation_work, yama_relation_cleanup); | ||
43 | |||
44 | /** | ||
45 | * yama_relation_cleanup - remove invalid entries from the relation list | ||
46 | * | ||
47 | */ | ||
48 | static void yama_relation_cleanup(struct work_struct *work) | ||
49 | { | ||
50 | struct ptrace_relation *relation; | ||
51 | |||
52 | spin_lock(&ptracer_relations_lock); | ||
53 | rcu_read_lock(); | ||
54 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { | ||
55 | if (relation->invalid) { | ||
56 | list_del_rcu(&relation->node); | ||
57 | kfree_rcu(relation, rcu); | ||
58 | } | ||
59 | } | ||
60 | rcu_read_unlock(); | ||
61 | spin_unlock(&ptracer_relations_lock); | ||
62 | } | ||
63 | |||
38 | /** | 64 | /** |
39 | * yama_ptracer_add - add/replace an exception for this tracer/tracee pair | 65 | * yama_ptracer_add - add/replace an exception for this tracer/tracee pair |
40 | * @tracer: the task_struct of the process doing the ptrace | 66 | * @tracer: the task_struct of the process doing the ptrace |
@@ -48,32 +74,34 @@ static DEFINE_SPINLOCK(ptracer_relations_lock); | |||
48 | static int yama_ptracer_add(struct task_struct *tracer, | 74 | static int yama_ptracer_add(struct task_struct *tracer, |
49 | struct task_struct *tracee) | 75 | struct task_struct *tracee) |
50 | { | 76 | { |
51 | int rc = 0; | 77 | struct ptrace_relation *relation, *added; |
52 | struct ptrace_relation *added; | ||
53 | struct ptrace_relation *entry, *relation = NULL; | ||
54 | 78 | ||
55 | added = kmalloc(sizeof(*added), GFP_KERNEL); | 79 | added = kmalloc(sizeof(*added), GFP_KERNEL); |
56 | if (!added) | 80 | if (!added) |
57 | return -ENOMEM; | 81 | return -ENOMEM; |
58 | 82 | ||
59 | spin_lock_bh(&ptracer_relations_lock); | 83 | added->tracee = tracee; |
60 | list_for_each_entry(entry, &ptracer_relations, node) | 84 | added->tracer = tracer; |
61 | if (entry->tracee == tracee) { | 85 | added->invalid = false; |
62 | relation = entry; | 86 | |
63 | break; | 87 | spin_lock(&ptracer_relations_lock); |
88 | rcu_read_lock(); | ||
89 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { | ||
90 | if (relation->invalid) | ||
91 | continue; | ||
92 | if (relation->tracee == tracee) { | ||
93 | list_replace_rcu(&relation->node, &added->node); | ||
94 | kfree_rcu(relation, rcu); | ||
95 | goto out; | ||
64 | } | 96 | } |
65 | if (!relation) { | ||
66 | relation = added; | ||
67 | relation->tracee = tracee; | ||
68 | list_add(&relation->node, &ptracer_relations); | ||
69 | } | 97 | } |
70 | relation->tracer = tracer; | ||
71 | 98 | ||
72 | spin_unlock_bh(&ptracer_relations_lock); | 99 | list_add_rcu(&added->node, &ptracer_relations); |
73 | if (added != relation) | ||
74 | kfree(added); | ||
75 | 100 | ||
76 | return rc; | 101 | out: |
102 | rcu_read_unlock(); | ||
103 | spin_unlock(&ptracer_relations_lock); | ||
104 | return 0; | ||
77 | } | 105 | } |
78 | 106 | ||
79 | /** | 107 | /** |
@@ -84,16 +112,23 @@ static int yama_ptracer_add(struct task_struct *tracer, | |||
84 | static void yama_ptracer_del(struct task_struct *tracer, | 112 | static void yama_ptracer_del(struct task_struct *tracer, |
85 | struct task_struct *tracee) | 113 | struct task_struct *tracee) |
86 | { | 114 | { |
87 | struct ptrace_relation *relation, *safe; | 115 | struct ptrace_relation *relation; |
116 | bool marked = false; | ||
88 | 117 | ||
89 | spin_lock_bh(&ptracer_relations_lock); | 118 | rcu_read_lock(); |
90 | list_for_each_entry_safe(relation, safe, &ptracer_relations, node) | 119 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { |
120 | if (relation->invalid) | ||
121 | continue; | ||
91 | if (relation->tracee == tracee || | 122 | if (relation->tracee == tracee || |
92 | (tracer && relation->tracer == tracer)) { | 123 | (tracer && relation->tracer == tracer)) { |
93 | list_del(&relation->node); | 124 | relation->invalid = true; |
94 | kfree(relation); | 125 | marked = true; |
95 | } | 126 | } |
96 | spin_unlock_bh(&ptracer_relations_lock); | 127 | } |
128 | rcu_read_unlock(); | ||
129 | |||
130 | if (marked) | ||
131 | schedule_work(&yama_relation_work); | ||
97 | } | 132 | } |
98 | 133 | ||
99 | /** | 134 | /** |
@@ -217,21 +252,22 @@ static int ptracer_exception_found(struct task_struct *tracer, | |||
217 | struct task_struct *parent = NULL; | 252 | struct task_struct *parent = NULL; |
218 | bool found = false; | 253 | bool found = false; |
219 | 254 | ||
220 | spin_lock_bh(&ptracer_relations_lock); | ||
221 | rcu_read_lock(); | 255 | rcu_read_lock(); |
222 | if (!thread_group_leader(tracee)) | 256 | if (!thread_group_leader(tracee)) |
223 | tracee = rcu_dereference(tracee->group_leader); | 257 | tracee = rcu_dereference(tracee->group_leader); |
224 | list_for_each_entry(relation, &ptracer_relations, node) | 258 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { |
259 | if (relation->invalid) | ||
260 | continue; | ||
225 | if (relation->tracee == tracee) { | 261 | if (relation->tracee == tracee) { |
226 | parent = relation->tracer; | 262 | parent = relation->tracer; |
227 | found = true; | 263 | found = true; |
228 | break; | 264 | break; |
229 | } | 265 | } |
266 | } | ||
230 | 267 | ||
231 | if (found && (parent == NULL || task_is_descendant(parent, tracer))) | 268 | if (found && (parent == NULL || task_is_descendant(parent, tracer))) |
232 | rc = 1; | 269 | rc = 1; |
233 | rcu_read_unlock(); | 270 | rcu_read_unlock(); |
234 | spin_unlock_bh(&ptracer_relations_lock); | ||
235 | 271 | ||
236 | return rc; | 272 | return rc; |
237 | } | 273 | } |
@@ -262,14 +298,18 @@ int yama_ptrace_access_check(struct task_struct *child, | |||
262 | /* No additional restrictions. */ | 298 | /* No additional restrictions. */ |
263 | break; | 299 | break; |
264 | case YAMA_SCOPE_RELATIONAL: | 300 | case YAMA_SCOPE_RELATIONAL: |
301 | rcu_read_lock(); | ||
265 | if (!task_is_descendant(current, child) && | 302 | if (!task_is_descendant(current, child) && |
266 | !ptracer_exception_found(current, child) && | 303 | !ptracer_exception_found(current, child) && |
267 | !ns_capable(task_user_ns(child), CAP_SYS_PTRACE)) | 304 | !ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE)) |
268 | rc = -EPERM; | 305 | rc = -EPERM; |
306 | rcu_read_unlock(); | ||
269 | break; | 307 | break; |
270 | case YAMA_SCOPE_CAPABILITY: | 308 | case YAMA_SCOPE_CAPABILITY: |
271 | if (!ns_capable(task_user_ns(child), CAP_SYS_PTRACE)) | 309 | rcu_read_lock(); |
310 | if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE)) | ||
272 | rc = -EPERM; | 311 | rc = -EPERM; |
312 | rcu_read_unlock(); | ||
273 | break; | 313 | break; |
274 | case YAMA_SCOPE_NO_ATTACH: | 314 | case YAMA_SCOPE_NO_ATTACH: |
275 | default: | 315 | default: |
@@ -307,8 +347,10 @@ int yama_ptrace_traceme(struct task_struct *parent) | |||
307 | /* Only disallow PTRACE_TRACEME on more aggressive settings. */ | 347 | /* Only disallow PTRACE_TRACEME on more aggressive settings. */ |
308 | switch (ptrace_scope) { | 348 | switch (ptrace_scope) { |
309 | case YAMA_SCOPE_CAPABILITY: | 349 | case YAMA_SCOPE_CAPABILITY: |
310 | if (!ns_capable(task_user_ns(parent), CAP_SYS_PTRACE)) | 350 | rcu_read_lock(); |
351 | if (!ns_capable(__task_cred(parent)->user_ns, CAP_SYS_PTRACE)) | ||
311 | rc = -EPERM; | 352 | rc = -EPERM; |
353 | rcu_read_unlock(); | ||
312 | break; | 354 | break; |
313 | case YAMA_SCOPE_NO_ATTACH: | 355 | case YAMA_SCOPE_NO_ATTACH: |
314 | rc = -EPERM; | 356 | rc = -EPERM; |