diff options
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r-- | security/keys/keyctl.c | 104 |
1 files changed, 32 insertions, 72 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index c2dd66d556d4..9b898c969558 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -37,8 +37,7 @@ static const unsigned char keyrings_capabilities[2] = { KEYCTL_CAPS0_MOVE ), [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME | - KEYCTL_CAPS1_NS_KEY_TAG | - KEYCTL_CAPS1_ACL_ALTERABLE), + KEYCTL_CAPS1_NS_KEY_TAG), }; static int key_get_type_from_user(char *type, @@ -131,7 +130,8 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, /* create or update the requested key and add it to the target * keyring */ key_ref = key_create_or_update(keyring_ref, type, description, - payload, plen, NULL, KEY_ALLOC_IN_QUOTA); + payload, plen, KEY_PERM_UNDEF, + KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key_ref)) { ret = key_ref_to_ptr(key_ref)->serial; key_ref_put(key_ref); @@ -221,8 +221,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, /* do the search */ key = request_key_and_link(ktype, description, NULL, callout_info, - callout_len, NULL, NULL, - key_ref_to_ptr(dest_ref), + callout_len, NULL, key_ref_to_ptr(dest_ref), KEY_ALLOC_IN_QUOTA); if (IS_ERR(key)) { ret = PTR_ERR(key); @@ -384,10 +383,16 @@ long keyctl_revoke_key(key_serial_t id) struct key *key; long ret; - key_ref = lookup_user_key(id, 0, KEY_NEED_REVOKE); + key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); - goto error; + if (ret != -EACCES) + goto error; + key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); + goto error; + } } key = key_ref_to_ptr(key_ref); @@ -421,7 +426,7 @@ long keyctl_invalidate_key(key_serial_t id) kenter("%d", id); - key_ref = lookup_user_key(id, 0, KEY_NEED_INVAL); + key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); @@ -466,7 +471,7 @@ long keyctl_keyring_clear(key_serial_t ringid) struct key *keyring; long ret; - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_CLEAR); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); @@ -641,7 +646,6 @@ long keyctl_describe_key(key_serial_t keyid, size_t buflen) { struct key *key, *instkey; - unsigned int perm; key_ref_t key_ref; char *infobuf; long ret; @@ -671,10 +675,6 @@ okay: key = key_ref_to_ptr(key_ref); desclen = strlen(key->description); - rcu_read_lock(); - perm = key_acl_to_perm(rcu_dereference(key->acl)); - rcu_read_unlock(); - /* calculate how much information we're going to return */ ret = -ENOMEM; infobuf = kasprintf(GFP_KERNEL, @@ -682,7 +682,7 @@ okay: key->type->name, from_kuid_munged(current_user_ns(), key->uid), from_kgid_munged(current_user_ns(), key->gid), - perm); + key->perm); if (!infobuf) goto error2; infolen = strlen(infobuf); @@ -899,7 +899,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) goto error; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_NEED_SETSEC); + KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -994,25 +994,18 @@ quota_overrun: * the key need not be fully instantiated yet. If the caller does not have * sysadmin capability, it may only change the permission on keys that it owns. */ -long keyctl_setperm_key(key_serial_t id, unsigned int perm) +long keyctl_setperm_key(key_serial_t id, key_perm_t perm) { - struct key_acl *acl; struct key *key; key_ref_t key_ref; long ret; - int nr, i, j; + ret = -EINVAL; if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) - return -EINVAL; - - nr = 0; - if (perm & KEY_POS_ALL) nr++; - if (perm & KEY_USR_ALL) nr++; - if (perm & KEY_GRP_ALL) nr++; - if (perm & KEY_OTH_ALL) nr++; + goto error; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_NEED_SETSEC); + KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -1020,45 +1013,17 @@ long keyctl_setperm_key(key_serial_t id, unsigned int perm) key = key_ref_to_ptr(key_ref); - ret = -EOPNOTSUPP; - if (test_bit(KEY_FLAG_HAS_ACL, &key->flags)) - goto error_key; + /* make the changes with the locks held to prevent chown/chmod races */ + ret = -EACCES; + down_write(&key->sem); - ret = -ENOMEM; - acl = kzalloc(struct_size(acl, aces, nr), GFP_KERNEL); - if (!acl) - goto error_key; - - refcount_set(&acl->usage, 1); - acl->nr_ace = nr; - j = 0; - for (i = 0; i < 4; i++) { - struct key_ace *ace = &acl->aces[j]; - unsigned int subset = (perm >> (i * 8)) & KEY_OTH_ALL; - - if (!subset) - continue; - ace->type = KEY_ACE_SUBJ_STANDARD; - ace->subject_id = KEY_ACE_EVERYONE + i; - ace->perm = subset; - if (subset & (KEY_OTH_WRITE | KEY_OTH_SETATTR)) - ace->perm |= KEY_ACE_REVOKE; - if (subset & KEY_OTH_SEARCH) - ace->perm |= KEY_ACE_INVAL; - if (key->type == &key_type_keyring) { - if (subset & KEY_OTH_SEARCH) - ace->perm |= KEY_ACE_JOIN; - if (subset & KEY_OTH_WRITE) - ace->perm |= KEY_ACE_CLEAR; - } - j++; + /* if we're not the sysadmin, we can only change a key that we own */ + if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { + key->perm = perm; + ret = 0; } - /* make the changes with the locks held to prevent chown/chmod races */ - down_write(&key->sem); - ret = key_set_acl(key, acl); up_write(&key->sem); -error_key: key_put(key); error: return ret; @@ -1423,7 +1388,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) long ret; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_NEED_SETSEC); + KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { /* setting the timeout on a key under construction is permitted * if we have the authorisation token handy */ @@ -1574,7 +1539,7 @@ long keyctl_get_security(key_serial_t keyid, * Attempt to install the calling process's session keyring on the process's * parent process. * - * The keyring must exist and must grant the caller JOIN permission, and the + * The keyring must exist and must grant the caller LINK permission, and the * parent process must be single-threaded and must have the same effective * ownership as this process and mustn't be SUID/SGID. * @@ -1591,7 +1556,7 @@ long keyctl_session_to_parent(void) struct cred *cred; int ret; - keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_JOIN); + keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK); if (IS_ERR(keyring_r)) return PTR_ERR(keyring_r); @@ -1693,7 +1658,7 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, char *restriction = NULL; long ret; - key_ref = lookup_user_key(id, 0, KEY_NEED_SETSEC); + key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); if (IS_ERR(key_ref)) return PTR_ERR(key_ref); @@ -1799,7 +1764,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, case KEYCTL_SETPERM: return keyctl_setperm_key((key_serial_t) arg2, - (unsigned int)arg3); + (key_perm_t) arg3); case KEYCTL_INSTANTIATE: return keyctl_instantiate_key((key_serial_t) arg2, @@ -1888,11 +1853,6 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, (key_serial_t)arg3, (key_serial_t)arg4, (unsigned int)arg5); - case KEYCTL_GRANT_PERMISSION: - return keyctl_grant_permission((key_serial_t)arg2, - (enum key_ace_subject_type)arg3, - (unsigned int)arg4, - (unsigned int)arg5); case KEYCTL_CAPABILITIES: return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3); |