diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/digsig.c | 31 | ||||
-rw-r--r-- | security/integrity/digsig_asymmetric.c | 2 | ||||
-rw-r--r-- | security/integrity/evm/evm_crypto.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_mok.c | 13 | ||||
-rw-r--r-- | security/integrity/integrity.h | 6 | ||||
-rw-r--r-- | security/integrity/platform_certs/platform_keyring.c | 14 | ||||
-rw-r--r-- | security/keys/compat.c | 2 | ||||
-rw-r--r-- | security/keys/encrypted-keys/encrypted.c | 2 | ||||
-rw-r--r-- | security/keys/encrypted-keys/masterkey_trusted.c | 2 | ||||
-rw-r--r-- | security/keys/gc.c | 2 | ||||
-rw-r--r-- | security/keys/internal.h | 16 | ||||
-rw-r--r-- | security/keys/key.c | 29 | ||||
-rw-r--r-- | security/keys/keyctl.c | 104 | ||||
-rw-r--r-- | security/keys/keyring.c | 27 | ||||
-rw-r--r-- | security/keys/permission.c | 361 | ||||
-rw-r--r-- | security/keys/persistent.c | 27 | ||||
-rw-r--r-- | security/keys/proc.c | 22 | ||||
-rw-r--r-- | security/keys/process_keys.c | 86 | ||||
-rw-r--r-- | security/keys/request_key.c | 34 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 15 | ||||
-rw-r--r-- | security/selinux/hooks.c | 16 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 3 |
22 files changed, 187 insertions, 629 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index f9f3c8ffe786..868ade3e8970 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -47,8 +47,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, if (!keyring[id]) { keyring[id] = - request_key(&key_type_keyring, keyring_name[id], - NULL, NULL); + request_key(&key_type_keyring, keyring_name[id], NULL); if (IS_ERR(keyring[id])) { int err = PTR_ERR(keyring[id]); pr_err("no %s keyring: %d\n", keyring_name[id], err); @@ -71,14 +70,14 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, } static int __init __integrity_init_keyring(const unsigned int id, - struct key_acl *acl, + key_perm_t perm, struct key_restriction *restriction) { const struct cred *cred = current_cred(); int err = 0; keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), - KGIDT_INIT(0), cred, acl, + KGIDT_INIT(0), cred, perm, KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL); if (IS_ERR(keyring[id])) { err = PTR_ERR(keyring[id]); @@ -96,7 +95,10 @@ static int __init __integrity_init_keyring(const unsigned int id, int __init integrity_init_keyring(const unsigned int id) { struct key_restriction *restriction; - struct key_acl *acl = &internal_keyring_acl; + key_perm_t perm; + + perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW + | KEY_USR_READ | KEY_USR_SEARCH; if (id == INTEGRITY_KEYRING_PLATFORM) { restriction = NULL; @@ -111,14 +113,14 @@ int __init integrity_init_keyring(const unsigned int id) return -ENOMEM; restriction->check = restrict_link_to_ima; - acl = &internal_writable_keyring_acl; + perm |= KEY_USR_WRITE; out: - return __integrity_init_keyring(id, acl, restriction); + return __integrity_init_keyring(id, perm, restriction); } -static int __init integrity_add_key(const unsigned int id, const void *data, - off_t size, struct key_acl *acl) +int __init integrity_add_key(const unsigned int id, const void *data, + off_t size, key_perm_t perm) { key_ref_t key; int rc = 0; @@ -127,7 +129,7 @@ static int __init integrity_add_key(const unsigned int id, const void *data, return -EINVAL; key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric", - NULL, data, size, acl ?: &internal_key_acl, + NULL, data, size, perm, KEY_ALLOC_NOT_IN_QUOTA); if (IS_ERR(key)) { rc = PTR_ERR(key); @@ -147,6 +149,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path) void *data; loff_t size; int rc; + key_perm_t perm; rc = kernel_read_file_from_path(path, &data, &size, 0, READING_X509_CERTIFICATE); @@ -155,19 +158,21 @@ int __init integrity_load_x509(const unsigned int id, const char *path) return rc; } + perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ; + pr_info("Loading X.509 certificate: %s\n", path); - rc = integrity_add_key(id, data, size, NULL); + rc = integrity_add_key(id, (const void *)data, size, perm); vfree(data); return rc; } int __init integrity_load_cert(const unsigned int id, const char *source, - const void *data, size_t len, struct key_acl *acl) + const void *data, size_t len, key_perm_t perm) { if (!data) return -EINVAL; pr_info("Loading X.509 certificate: %s\n", source); - return integrity_add_key(id, data, len, acl); + return integrity_add_key(id, data, len, perm); } diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index a29df775fdd8..55aec161d0e1 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -53,7 +53,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) else key = key_ref_to_ptr(kref); } else { - key = request_key(&key_type_asymmetric, name, NULL, NULL); + key = request_key(&key_type_asymmetric, name, NULL); } if (IS_ERR(key)) { diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 466eebd3b4aa..d485f6fc908e 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -356,7 +356,7 @@ int evm_init_key(void) struct encrypted_key_payload *ekp; int rc; - evm_key = request_key(&key_type_encrypted, EVMKEY, NULL, NULL); + evm_key = request_key(&key_type_encrypted, EVMKEY, NULL); if (IS_ERR(evm_key)) return -ENOENT; diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c index b52ae1476ec3..36cadadbfba4 100644 --- a/security/integrity/ima/ima_mok.c +++ b/security/integrity/ima/ima_mok.c @@ -16,15 +16,6 @@ #include <keys/system_keyring.h> -static struct key_acl integrity_blacklist_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH), - } -}; - struct key *ima_blacklist_keyring; /* @@ -44,7 +35,9 @@ __init int ima_mok_init(void) ima_blacklist_keyring = keyring_alloc(".ima_blacklist", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - &integrity_blacklist_keyring_acl, + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | + KEY_USR_WRITE | KEY_USR_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL); diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 875c6a7a5af1..ed12d8e13d04 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -12,8 +12,6 @@ #include <linux/key.h> #include <linux/audit.h> -struct key_acl; - /* iint action cache flags */ #define IMA_MEASURE 0x00000001 #define IMA_MEASURED 0x00000002 @@ -157,7 +155,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int __init integrity_init_keyring(const unsigned int id); int __init integrity_load_x509(const unsigned int id, const char *path); int __init integrity_load_cert(const unsigned int id, const char *source, - const void *data, size_t len, struct key_acl *acl); + const void *data, size_t len, key_perm_t perm); #else static inline int integrity_digsig_verify(const unsigned int id, @@ -175,7 +173,7 @@ static inline int integrity_init_keyring(const unsigned int id) static inline int __init integrity_load_cert(const unsigned int id, const char *source, const void *data, size_t len, - struct key_acl *acl) + key_perm_t perm) { return 0; } diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c index 7646e35f2d91..bcafd7387729 100644 --- a/security/integrity/platform_certs/platform_keyring.c +++ b/security/integrity/platform_certs/platform_keyring.c @@ -14,15 +14,6 @@ #include <linux/slab.h> #include "../integrity.h" -static struct key_acl platform_key_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_READ), - KEY_OWNER_ACE(KEY_ACE_VIEW), - } -}; - /** * add_to_platform_keyring - Add to platform keyring without validation. * @source: Source of key @@ -35,10 +26,13 @@ static struct key_acl platform_key_acl = { void __init add_to_platform_keyring(const char *source, const void *data, size_t len) { + key_perm_t perm; int rc; + perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW; + rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source, data, len, - &platform_key_acl); + perm); if (rc) pr_info("Error adding keys to platform keyring %s\n", source); } diff --git a/security/keys/compat.c b/security/keys/compat.c index b0e59546e7bd..9bcc404131aa 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -157,8 +157,6 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, case KEYCTL_MOVE: return keyctl_keyring_move(arg2, arg3, arg4, arg5); - case KEYCTL_GRANT_PERMISSION: - return keyctl_grant_permission(arg2, arg3, arg4, arg5); case KEYCTL_CAPABILITIES: return keyctl_capabilities(compat_ptr(arg2), arg3); diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 9df560e477c2..60720f58cbe0 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -304,7 +304,7 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k const struct user_key_payload *upayload; struct key *ukey; - ukey = request_key(&key_type_user, master_desc, NULL, NULL); + ukey = request_key(&key_type_user, master_desc, NULL); if (IS_ERR(ukey)) goto error; diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c index d649f2f29475..c68528aa49c6 100644 --- a/security/keys/encrypted-keys/masterkey_trusted.c +++ b/security/keys/encrypted-keys/masterkey_trusted.c @@ -30,7 +30,7 @@ struct key *request_trusted_key(const char *trusted_desc, struct trusted_key_payload *tpayload; struct key *tkey; - tkey = request_key(&key_type_trusted, trusted_desc, NULL, NULL); + tkey = request_key(&key_type_trusted, trusted_desc, NULL); if (IS_ERR(tkey)) goto error; diff --git a/security/keys/gc.c b/security/keys/gc.c index 48c3e124c272..671dd730ecfc 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -151,7 +151,6 @@ static noinline void key_gc_unused_keys(struct list_head *keys) key_user_put(key->user); key_put_tag(key->domain_tag); - key_put_acl(rcu_access_pointer(key->acl)); kfree(key->description); memzero_explicit(key, sizeof(*key)); @@ -221,6 +220,7 @@ continue_scanning: if (key->type == key_gc_dead_keytype) { gc_state |= KEY_GC_FOUND_DEAD_KEY; set_bit(KEY_FLAG_DEAD, &key->flags); + key->perm = 0; goto skip_dead_key; } else if (key->type == &key_type_keyring && key->restrict_link) { diff --git a/security/keys/internal.h b/security/keys/internal.h index e0c5bb8b1685..c039373488bd 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -84,11 +84,8 @@ extern struct rb_root key_serial_tree; extern spinlock_t key_serial_lock; extern struct mutex key_construction_mutex; extern wait_queue_head_t request_key_conswq; -extern struct key_acl default_key_acl; -extern struct key_acl joinable_keyring_acl; extern void key_set_index_key(struct keyring_index_key *index_key); - extern struct key_type *key_type_lookup(const char *type); extern void key_type_put(struct key_type *ktype); @@ -159,7 +156,6 @@ extern struct key *request_key_and_link(struct key_type *type, const void *callout_info, size_t callout_len, void *aux, - struct key_acl *acl, struct key *dest_keyring, unsigned long flags); @@ -183,10 +179,7 @@ extern void key_gc_keytype(struct key_type *ktype); extern int key_task_permission(const key_ref_t key_ref, const struct cred *cred, - u32 desired_perm); -extern unsigned int key_acl_to_perm(const struct key_acl *acl); -extern long key_set_acl(struct key *key, struct key_acl *acl); -extern void key_put_acl(struct key_acl *acl); + key_perm_t perm); /* * Check to see whether permission is granted to use a key in the desired way. @@ -233,7 +226,7 @@ extern long keyctl_keyring_search(key_serial_t, const char __user *, const char __user *, key_serial_t); extern long keyctl_read_key(key_serial_t, char __user *, size_t); extern long keyctl_chown_key(key_serial_t, uid_t, gid_t); -extern long keyctl_setperm_key(key_serial_t, unsigned int); +extern long keyctl_setperm_key(key_serial_t, key_perm_t); extern long keyctl_instantiate_key(key_serial_t, const void __user *, size_t, key_serial_t); extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); @@ -338,11 +331,6 @@ static inline long keyctl_pkey_e_d_s(int op, extern long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen); -extern long keyctl_grant_permission(key_serial_t keyid, - enum key_ace_subject_type type, - unsigned int subject, - unsigned int perm); - /* * Debugging key validation */ diff --git a/security/keys/key.c b/security/keys/key.c index 519211a996e7..764f4c57913e 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -195,7 +195,7 @@ serial_exists: * @uid: The owner of the new key. * @gid: The group ID for the new key's group permissions. * @cred: The credentials specifying UID namespace. - * @acl: The ACL to attach to the new key. + * @perm: The permissions mask of the new key. * @flags: Flags specifying quota properties. * @restrict_link: Optional link restriction for new keyrings. * @@ -223,7 +223,7 @@ serial_exists: */ struct key *key_alloc(struct key_type *type, const char *desc, kuid_t uid, kgid_t gid, const struct cred *cred, - struct key_acl *acl, unsigned long flags, + key_perm_t perm, unsigned long flags, struct key_restriction *restrict_link) { struct key_user *user = NULL; @@ -246,9 +246,6 @@ struct key *key_alloc(struct key_type *type, const char *desc, desclen = strlen(desc); quotalen = desclen + 1 + type->def_datalen; - if (!acl) - acl = &default_key_acl; - /* get hold of the key tracking for this user */ user = key_user_lookup(uid); if (!user) @@ -295,8 +292,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->datalen = type->def_datalen; key->uid = uid; key->gid = gid; - refcount_inc(&acl->usage); - rcu_assign_pointer(key->acl, acl); + key->perm = perm; key->restrict_link = restrict_link; key->last_used_at = ktime_get_real_seconds(); @@ -791,7 +787,7 @@ error: * @description: The searchable description for the key. * @payload: The data to use to instantiate or update the key. * @plen: The length of @payload. - * @acl: The ACL to attach if a key is created. + * @perm: The permissions mask for a new key. * @flags: The quota flags for a new key. * * Search the destination keyring for a key of the same description and if one @@ -814,7 +810,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, const char *description, const void *payload, size_t plen, - struct key_acl *acl, + key_perm_t perm, unsigned long flags) { struct keyring_index_key index_key = { @@ -911,9 +907,22 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, goto found_matching_key; } + /* if the client doesn't provide, decide on the permissions we want */ + if (perm == KEY_PERM_UNDEF) { + perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; + perm |= KEY_USR_VIEW; + + if (index_key.type->read) + perm |= KEY_POS_READ; + + if (index_key.type == &key_type_keyring || + index_key.type->update) + perm |= KEY_POS_WRITE; + } + /* allocate a new key */ key = key_alloc(index_key.type, index_key.description, - cred->fsuid, cred->fsgid, cred, acl, flags, NULL); + cred->fsuid, cred->fsgid, cred, perm, flags, NULL); if (IS_ERR(key)) { key_ref = ERR_CAST(key); goto error_link_end; 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); diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 3b5458f23a95..febf36c6ddc5 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -515,19 +515,11 @@ static long keyring_read(const struct key *keyring, return ret; } -/** - * keyring_alloc - Allocate a keyring and link into the destination - * @description: The key description to allow the key to be searched out. - * @uid: The owner of the new key. - * @gid: The group ID for the new key's group permissions. - * @cred: The credentials specifying UID namespace. - * @acl: The ACL to attach to the new key. - * @flags: Flags specifying quota properties. - * @restrict_link: Optional link restriction for new keyrings. - * @dest: Destination keyring. +/* + * Allocate a keyring and link into the destination keyring. */ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, - const struct cred *cred, struct key_acl *acl, + const struct cred *cred, key_perm_t perm, unsigned long flags, struct key_restriction *restrict_link, struct key *dest) @@ -536,7 +528,7 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, int ret; keyring = key_alloc(&key_type_keyring, description, - uid, gid, cred, acl, flags, restrict_link); + uid, gid, cred, perm, flags, restrict_link); if (!IS_ERR(keyring)) { ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); if (ret < 0) { @@ -1140,11 +1132,10 @@ found: /* * Find a keyring with the specified name. * - * Only keyrings that have nonzero refcount, are not revoked, and are owned by - * a user in the current user namespace are considered. If @uid_keyring is - * %true, the keyring additionally must have been allocated as a user or user - * session keyring; otherwise, it must grant JOIN permission directly to the - * caller (ie. not through possession). + * Only keyrings that have nonzero refcount, are not revoked, and are owned by a + * user in the current user namespace are considered. If @uid_keyring is %true, + * the keyring additionally must have been allocated as a user or user session + * keyring; otherwise, it must grant Search permission directly to the caller. * * Returns a pointer to the keyring with the keyring's refcount having being * incremented on success. -ENOKEY is returned if a key could not be found. @@ -1178,7 +1169,7 @@ struct key *find_keyring_by_name(const char *name, bool uid_keyring) continue; } else { if (key_permission(make_key_ref(keyring, 0), - KEY_NEED_JOIN) < 0) + KEY_NEED_SEARCH) < 0) continue; } diff --git a/security/keys/permission.c b/security/keys/permission.c index fd8a5dc6910a..085f907b64ac 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c @@ -7,67 +7,13 @@ #include <linux/export.h> #include <linux/security.h> -#include <linux/user_namespace.h> -#include <linux/uaccess.h> #include "internal.h" -struct key_acl default_key_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .possessor_viewable = true, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN), - KEY_OWNER_ACE(KEY_ACE_VIEW), - } -}; -EXPORT_SYMBOL(default_key_acl); - -struct key_acl joinable_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .possessor_viewable = true, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_LINK | KEY_ACE_JOIN), - } -}; -EXPORT_SYMBOL(joinable_keyring_acl); - -struct key_acl internal_key_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_SEARCH), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH), - } -}; -EXPORT_SYMBOL(internal_key_acl); - -struct key_acl internal_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_SEARCH), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH), - } -}; -EXPORT_SYMBOL(internal_keyring_acl); - -struct key_acl internal_writable_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH), - } -}; -EXPORT_SYMBOL(internal_writable_keyring_acl); - /** * key_task_permission - Check a key can be used * @key_ref: The key to check. * @cred: The credentials to use. - * @desired_perm: The permission to check for. + * @perm: The permissions to check for. * * Check to see whether permission is granted to use a key in the desired way, * but permit the security modules to override. @@ -78,73 +24,53 @@ EXPORT_SYMBOL(internal_writable_keyring_acl); * permissions bits or the LSM check. */ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, - unsigned int desired_perm) + unsigned perm) { - const struct key_acl *acl; - const struct key *key; - unsigned int allow = 0; - int i; - - BUILD_BUG_ON(KEY_NEED_VIEW != KEY_ACE_VIEW || - KEY_NEED_READ != KEY_ACE_READ || - KEY_NEED_WRITE != KEY_ACE_WRITE || - KEY_NEED_SEARCH != KEY_ACE_SEARCH || - KEY_NEED_LINK != KEY_ACE_LINK || - KEY_NEED_SETSEC != KEY_ACE_SET_SECURITY || - KEY_NEED_INVAL != KEY_ACE_INVAL || - KEY_NEED_REVOKE != KEY_ACE_REVOKE || - KEY_NEED_JOIN != KEY_ACE_JOIN || - KEY_NEED_CLEAR != KEY_ACE_CLEAR); + struct key *key; + key_perm_t kperm; + int ret; key = key_ref_to_ptr(key_ref); - rcu_read_lock(); - - acl = rcu_dereference(key->acl); - if (!acl || acl->nr_ace == 0) - goto no_access_rcu; + /* use the second 8-bits of permissions for keys the caller owns */ + if (uid_eq(key->uid, cred->fsuid)) { + kperm = key->perm >> 16; + goto use_these_perms; + } - for (i = 0; i < acl->nr_ace; i++) { - const stru |