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 | 20 | ||||
| -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 | 94 | ||||
| -rw-r--r-- | security/keys/request_key.c | 21 | ||||
| -rw-r--r-- | security/security.c | 10 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 3 | ||||
| -rw-r--r-- | security/smack/Kconfig | 6 | ||||
| -rw-r--r-- | security/smack/smackfs.c | 17 | ||||
| -rw-r--r-- | security/yama/yama_lsm.c | 100 |
17 files changed, 241 insertions, 122 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 b08d20c66c2e..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,6 +169,8 @@ 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_rcu(&ex->list); | 175 | list_del_rcu(&ex->list); |
| 168 | kfree_rcu(ex, rcu); | 176 | kfree_rcu(ex, rcu); |
| @@ -172,7 +180,7 @@ static void dev_exception_clean(struct dev_cgroup *dev_cgroup) | |||
| 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,6 +306,10 @@ 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 | ||
| 309 | rcu_lockdep_assert(rcu_read_lock_held() || | ||
| 310 | lockdep_is_held(&devcgroup_mutex), | ||
| 311 | "device_cgroup::may_access() called without proper synchronization"); | ||
| 312 | |||
| 301 | list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) { | 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; |
| @@ -552,8 +564,8 @@ static struct cftype dev_cgroup_files[] = { | |||
| 552 | struct cgroup_subsys devices_subsys = { | 564 | struct cgroup_subsys devices_subsys = { |
| 553 | .name = "devices", | 565 | .name = "devices", |
| 554 | .can_attach = devcgroup_can_attach, | 566 | .can_attach = devcgroup_can_attach, |
| 555 | .create = devcgroup_create, | 567 | .css_alloc = devcgroup_css_alloc, |
| 556 | .destroy = devcgroup_destroy, | 568 | .css_free = devcgroup_css_free, |
| 557 | .subsys_id = devices_subsys_id, | 569 | .subsys_id = devices_subsys_id, |
| 558 | .base_cftypes = dev_cgroup_files, | 570 | .base_cftypes = dev_cgroup_files, |
| 559 | 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..58dfe0890947 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,9 +358,9 @@ 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; |
| @@ -391,12 +379,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
| 391 | } | 379 | } |
| 392 | 380 | ||
| 393 | /* search the session keyring */ | 381 | /* search the session keyring */ |
| 394 | if (cred->tgcred->session_keyring) { | 382 | if (cred->session_keyring) { |
| 395 | rcu_read_lock(); | 383 | rcu_read_lock(); |
| 396 | key_ref = keyring_search_aux( | 384 | key_ref = keyring_search_aux( |
| 397 | make_key_ref(rcu_dereference( | 385 | make_key_ref(rcu_dereference(cred->session_keyring), 1), |
| 398 | cred->tgcred->session_keyring), | ||
| 399 | 1), | ||
| 400 | cred, type, description, match, no_state_check); | 386 | cred, type, description, match, no_state_check); |
| 401 | rcu_read_unlock(); | 387 | rcu_read_unlock(); |
| 402 | 388 | ||
| @@ -566,7 +552,7 @@ try_again: | |||
| 566 | break; | 552 | break; |
| 567 | 553 | ||
| 568 | case KEY_SPEC_PROCESS_KEYRING: | 554 | case KEY_SPEC_PROCESS_KEYRING: |
| 569 | if (!cred->tgcred->process_keyring) { | 555 | if (!cred->process_keyring) { |
| 570 | if (!(lflags & KEY_LOOKUP_CREATE)) | 556 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 571 | goto error; | 557 | goto error; |
| 572 | 558 | ||
| @@ -578,13 +564,13 @@ try_again: | |||
| 578 | goto reget_creds; | 564 | goto reget_creds; |
| 579 | } | 565 | } |
| 580 | 566 | ||
| 581 | key = cred->tgcred->process_keyring; | 567 | key = cred->process_keyring; |
| 582 | atomic_inc(&key->usage); | 568 | atomic_inc(&key->usage); |
| 583 | key_ref = make_key_ref(key, 1); | 569 | key_ref = make_key_ref(key, 1); |
| 584 | break; | 570 | break; |
| 585 | 571 | ||
| 586 | case KEY_SPEC_SESSION_KEYRING: | 572 | case KEY_SPEC_SESSION_KEYRING: |
| 587 | if (!cred->tgcred->session_keyring) { | 573 | if (!cred->session_keyring) { |
| 588 | /* always install a session keyring upon access if one | 574 | /* always install a session keyring upon access if one |
| 589 | * doesn't exist yet */ | 575 | * doesn't exist yet */ |
| 590 | ret = install_user_keyrings(); | 576 | ret = install_user_keyrings(); |
| @@ -599,7 +585,7 @@ try_again: | |||
| 599 | if (ret < 0) | 585 | if (ret < 0) |
| 600 | goto error; | 586 | goto error; |
| 601 | goto reget_creds; | 587 | goto reget_creds; |
| 602 | } else if (cred->tgcred->session_keyring == | 588 | } else if (cred->session_keyring == |
| 603 | cred->user->session_keyring && | 589 | cred->user->session_keyring && |
| 604 | lflags & KEY_LOOKUP_CREATE) { | 590 | lflags & KEY_LOOKUP_CREATE) { |
| 605 | ret = join_session_keyring(NULL); | 591 | ret = join_session_keyring(NULL); |
| @@ -609,7 +595,7 @@ try_again: | |||
| 609 | } | 595 | } |
| 610 | 596 | ||
| 611 | rcu_read_lock(); | 597 | rcu_read_lock(); |
| 612 | key = rcu_dereference(cred->tgcred->session_keyring); | 598 | key = rcu_dereference(cred->session_keyring); |
| 613 | atomic_inc(&key->usage); | 599 | atomic_inc(&key->usage); |
| 614 | rcu_read_unlock(); | 600 | rcu_read_unlock(); |
| 615 | key_ref = make_key_ref(key, 1); | 601 | key_ref = make_key_ref(key, 1); |
| @@ -769,12 +755,6 @@ long join_session_keyring(const char *name) | |||
| 769 | struct key *keyring; | 755 | struct key *keyring; |
| 770 | long ret, serial; | 756 | long ret, serial; |
| 771 | 757 | ||
| 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(); | 758 | new = prepare_creds(); |
| 779 | if (!new) | 759 | if (!new) |
| 780 | return -ENOMEM; | 760 | return -ENOMEM; |
| @@ -786,7 +766,7 @@ long join_session_keyring(const char *name) | |||
| 786 | if (ret < 0) | 766 | if (ret < 0) |
| 787 | goto error; | 767 | goto error; |
| 788 | 768 | ||
| 789 | serial = new->tgcred->session_keyring->serial; | 769 | serial = new->session_keyring->serial; |
| 790 | ret = commit_creds(new); | 770 | ret = commit_creds(new); |
| 791 | if (ret == 0) | 771 | if (ret == 0) |
| 792 | ret = serial; | 772 | ret = serial; |
| @@ -800,8 +780,10 @@ long join_session_keyring(const char *name) | |||
| 800 | keyring = find_keyring_by_name(name, false); | 780 | keyring = find_keyring_by_name(name, false); |
| 801 | if (PTR_ERR(keyring) == -ENOKEY) { | 781 | if (PTR_ERR(keyring) == -ENOKEY) { |
| 802 | /* not found - try and create a new one */ | 782 | /* not found - try and create a new one */ |
| 803 | keyring = keyring_alloc(name, old->uid, old->gid, old, | 783 | keyring = keyring_alloc( |
| 804 | KEY_ALLOC_IN_QUOTA, NULL); | 784 | name, old->uid, old->gid, old, |
| 785 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, | ||
| 786 | KEY_ALLOC_IN_QUOTA, NULL); | ||
| 805 | if (IS_ERR(keyring)) { | 787 | if (IS_ERR(keyring)) { |
| 806 | ret = PTR_ERR(keyring); | 788 | ret = PTR_ERR(keyring); |
| 807 | goto error2; | 789 | goto error2; |
| @@ -809,6 +791,9 @@ long join_session_keyring(const char *name) | |||
| 809 | } else if (IS_ERR(keyring)) { | 791 | } else if (IS_ERR(keyring)) { |
| 810 | ret = PTR_ERR(keyring); | 792 | ret = PTR_ERR(keyring); |
| 811 | goto error2; | 793 | goto error2; |
| 794 | } else if (keyring == new->session_keyring) { | ||
| 795 | ret = 0; | ||
| 796 | goto error2; | ||
| 812 | } | 797 | } |
| 813 | 798 | ||
| 814 | /* we've got a keyring - now to install it */ | 799 | /* we've got a keyring - now to install it */ |
| @@ -865,8 +850,7 @@ void key_change_session_keyring(struct callback_head *twork) | |||
| 865 | 850 | ||
| 866 | new->jit_keyring = old->jit_keyring; | 851 | new->jit_keyring = old->jit_keyring; |
| 867 | new->thread_keyring = key_get(old->thread_keyring); | 852 | new->thread_keyring = key_get(old->thread_keyring); |
| 868 | new->tgcred->tgid = old->tgcred->tgid; | 853 | new->process_keyring = key_get(old->process_keyring); |
| 869 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
| 870 | 854 | ||
| 871 | security_transfer_creds(new, old); | 855 | security_transfer_creds(new, old); |
| 872 | 856 | ||
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/nlmsgtab.c b/security/selinux/nlmsgtab.c index d309e7f472d8..370a6468b3ba 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -67,6 +67,9 @@ 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_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | ||
| 70 | }; | 73 | }; |
| 71 | 74 | ||
| 72 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | 75 | 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; |
