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 struct key_ace *ace = &acl->aces[i]; + /* use the third 8-bits of permissions for keys the caller has a group + * membership in common with */ + if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) { + if (gid_eq(key->gid, cred->fsgid)) { + kperm = key->perm >> 8; + goto use_these_perms; + } - switch (ace->type) { - case KEY_ACE_SUBJ_STANDARD: - switch (ace->subject_id) { - case KEY_ACE_POSSESSOR: - if (is_key_possessed(key_ref)) - allow |= ace->perm; - break; - case KEY_ACE_OWNER: - if (uid_eq(key->uid, cred->fsuid)) - allow |= ace->perm; - break; - case KEY_ACE_GROUP: - if (gid_valid(key->gid)) { - if (gid_eq(key->gid, cred->fsgid)) - allow |= ace->perm; - else if (groups_search(cred->group_info, key->gid)) - allow |= ace->perm; - } - break; - case KEY_ACE_EVERYONE: - allow |= ace->perm; - break; - } - break; + ret = groups_search(cred->group_info, key->gid); + if (ret) { + kperm = key->perm >> 8; + goto use_these_perms; } } - rcu_read_unlock(); + /* otherwise use the least-significant 8-bits */ + kperm = key->perm; + +use_these_perms: - if (!(allow & desired_perm)) - goto no_access; + /* use the top 8-bits of permissions for keys the caller possesses + * - possessor permissions are additive with other permissions + */ + if (is_key_possessed(key_ref)) + kperm |= key->perm >> 24; - return security_key_permission(key_ref, cred, desired_perm); + kperm = kperm & perm & KEY_NEED_ALL; -no_access_rcu: - rcu_read_unlock(); -no_access: - return -EACCES; + if (kperm != perm) + return -EACCES; + + /* let LSM be the final arbiter */ + return security_key_permission(key_ref, cred, perm); } EXPORT_SYMBOL(key_task_permission); @@ -178,218 +104,3 @@ int key_validate(const struct key *key) return 0; } EXPORT_SYMBOL(key_validate); - -/* - * Roughly render an ACL to an old-style permissions mask. We cannot - * accurately render what the ACL, particularly if it has ACEs that represent - * subjects outside of { poss, user, group, other }. - */ -unsigned int key_acl_to_perm(const struct key_acl *acl) -{ - unsigned int perm = 0, tperm; - int i; - - BUILD_BUG_ON(KEY_OTH_VIEW != KEY_ACE_VIEW || - KEY_OTH_READ != KEY_ACE_READ || - KEY_OTH_WRITE != KEY_ACE_WRITE || - KEY_OTH_SEARCH != KEY_ACE_SEARCH || - KEY_OTH_LINK != KEY_ACE_LINK || - KEY_OTH_SETATTR != KEY_ACE_SET_SECURITY); - - if (!acl || acl->nr_ace == 0) - return 0; - - for (i = 0; i < acl->nr_ace; i++) { - const struct key_ace *ace = &acl->aces[i]; - - switch (ace->type) { - case KEY_ACE_SUBJ_STANDARD: - tperm = ace->perm & KEY_OTH_ALL; - - /* Invalidation and joining were allowed by SEARCH */ - if (ace->perm & (KEY_ACE_INVAL | KEY_ACE_JOIN)) - tperm |= KEY_OTH_SEARCH; - - /* Revocation was allowed by either SETATTR or WRITE */ - if ((ace->perm & KEY_ACE_REVOKE) && !(tperm & KEY_OTH_SETATTR)) - tperm |= KEY_OTH_WRITE; - - /* Clearing was allowed by WRITE */ - if (ace->perm & KEY_ACE_CLEAR) - tperm |= KEY_OTH_WRITE; - - switch (ace->subject_id) { - case KEY_ACE_POSSESSOR: - perm |= tperm << 24; - break; - case KEY_ACE_OWNER: - perm |= tperm << 16; - break; - case KEY_ACE_GROUP: - perm |= tperm << 8; - break; - case KEY_ACE_EVERYONE: - perm |= tperm << 0; - break; - } - } - } - - return perm; -} - -/* - * Destroy a key's ACL. - */ -void key_put_acl(struct key_acl *acl) -{ - if (acl && refcount_dec_and_test(&acl->usage)) - kfree_rcu(acl, rcu); -} - -/* - * Try to set the ACL. This either attaches or discards the proposed ACL. - */ -long key_set_acl(struct key *key, struct key_acl *acl) -{ - int i; - - /* 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_put_acl(acl); - return -EACCES; - } - - for (i = 0; i < acl->nr_ace; i++) { - const struct key_ace *ace = &acl->aces[i]; - if (ace->type == KEY_ACE_SUBJ_STANDARD && - ace->subject_id == KEY_ACE_POSSESSOR) { - if (ace->perm & KEY_ACE_VIEW) - acl->possessor_viewable = true; - break; - } - } - - rcu_swap_protected(key->acl, acl, lockdep_is_held(&key->sem)); - key_put_acl(acl); - return 0; -} - -/* - * Allocate a new ACL with an extra ACE slot. - */ -static struct key_acl *key_alloc_acl(const struct key_acl *old_acl, int nr, int skip) -{ - struct key_acl *acl; - int nr_ace, i, j = 0; - - nr_ace = old_acl->nr_ace + nr; - if (nr_ace > 16) - return ERR_PTR(-EINVAL); - - acl = kzalloc(struct_size(acl, aces, nr_ace), GFP_KERNEL); - if (!acl) - return ERR_PTR(-ENOMEM); - - refcount_set(&acl->usage, 1); - acl->nr_ace = nr_ace; - for (i = 0; i < old_acl->nr_ace; i++) { - if (i == skip) - continue; - acl->aces[j] = old_acl->aces[i]; - j++; - } - return acl; -} - -/* - * Generate the revised ACL. - */ -static long key_change_acl(struct key *key, struct key_ace *new_ace) -{ - struct key_acl *acl, *old; - int i; - - old = rcu_dereference_protected(key->acl, lockdep_is_held(&key->sem)); - - for (i = 0; i < old->nr_ace; i++) - if (old->aces[i].type == new_ace->type && - old->aces[i].subject_id == new_ace->subject_id) - goto found_match; - - if (new_ace->perm == 0) - return 0; /* No permissions to remove. Add deny record? */ - - acl = key_alloc_acl(old, 1, -1); - if (IS_ERR(acl)) - return PTR_ERR(acl); - acl->aces[i] = *new_ace; - goto change; - -found_match: - if (new_ace->perm == 0) - goto delete_ace; - if (new_ace->perm == old->aces[i].perm) - return 0; - acl = key_alloc_acl(old, 0, -1); - if (IS_ERR(acl)) - return PTR_ERR(acl); - acl->aces[i].perm = new_ace->perm; - goto change; - -delete_ace: - acl = key_alloc_acl(old, -1, i); - if (IS_ERR(acl)) - return PTR_ERR(acl); - goto change; - -change: - return key_set_acl(key, acl); -} - -/* - * Add, alter or remove (if perm == 0) an ACE in a key's ACL. - */ -long keyctl_grant_permission(key_serial_t keyid, - enum key_ace_subject_type type, - unsigned int subject, - unsigned int perm) -{ - struct key_ace new_ace; - struct key *key; - key_ref_t key_ref; - long ret; - - new_ace.type = type; - new_ace.perm = perm; - - switch (type) { - case KEY_ACE_SUBJ_STANDARD: - if (subject >= nr__key_ace_standard_subject) - return -ENOENT; - new_ace.subject_id = subject; - break; - - default: - return -ENOENT; - } - - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_SETSEC); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error; - } - - key = key_ref_to_ptr(key_ref); - - down_write(&key->sem); - - /* If we're not the sysadmin, we can only change a key that we own */ - ret = -EACCES; - if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) - ret = key_change_acl(key, &new_ace); - up_write(&key->sem); - key_put(key); -error: - return ret; -} diff --git a/security/keys/persistent.c b/security/keys/persistent.c index 8171c90d4c9a..97af230aa4b2 100644 --- a/security/keys/persistent.c +++ b/security/keys/persistent.c @@ -12,27 +12,6 @@ unsigned persistent_keyring_expiry = 3 * 24 * 3600; /* Expire after 3 days of non-use */ -static struct key_acl persistent_register_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), - } -}; - -static struct key_acl persistent_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .possessor_viewable = true, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | - KEY_ACE_SEARCH | KEY_ACE_LINK | - KEY_ACE_CLEAR | KEY_ACE_INVAL), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), - } -}; - /* * Create the persistent keyring register for the current user namespace. * @@ -43,7 +22,8 @@ static int key_create_persistent_register(struct user_namespace *ns) struct key *reg = keyring_alloc(".persistent_register", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - &persistent_register_keyring_acl, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ), KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); if (IS_ERR(reg)) return PTR_ERR(reg); @@ -76,7 +56,8 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid, persistent = keyring_alloc(index_key->description, uid, INVALID_GID, current_cred(), - &persistent_keyring_acl, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ), KEY_ALLOC_NOT_IN_QUOTA, NULL, ns->persistent_keyring_register); if (IS_ERR(persistent)) diff --git a/security/keys/proc.c b/security/keys/proc.c index b394ad1e874b..415f3f1c2da0 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -110,13 +110,11 @@ static struct key *find_ge_key(struct seq_file *p, key_serial_t id) } static void *proc_keys_start(struct seq_file *p, loff_t *_pos) - __acquires(rcu) __acquires(key_serial_lock) { key_serial_t pos = *_pos; struct key *key; - rcu_read_lock(); spin_lock(&key_serial_lock); if (*_pos > INT_MAX) @@ -146,15 +144,12 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) static void proc_keys_stop(struct seq_file *p, void *v) __releases(key_serial_lock) - __releases(rcu) { spin_unlock(&key_serial_lock); - rcu_read_unlock(); } static int proc_keys_show(struct seq_file *m, void *v) { - const struct key_acl *acl; struct rb_node *_p = v; struct key *key = rb_entry(_p, struct key, serial_node); unsigned long flags; @@ -162,7 +157,6 @@ static int proc_keys_show(struct seq_file *m, void *v) time64_t now, expiry; char xbuf[16]; short state; - bool check_pos; u64 timo; int rc; @@ -176,15 +170,15 @@ static int proc_keys_show(struct seq_file *m, void *v) KEYRING_SEARCH_RECURSE), }; - acl = rcu_dereference(key->acl); - check_pos = acl->possessor_viewable; + key_ref = make_key_ref(key, 0); /* determine if the key is possessed by this process (a test we can * skip if the key does not indicate the possessor can view it */ - key_ref = make_key_ref(key, 0); - if (check_pos) { + if (key->perm & KEY_POS_VIEW) { + rcu_read_lock(); skey_ref = search_cred_keyrings_rcu(&ctx); + rcu_read_unlock(); if (!IS_ERR(skey_ref)) { key_ref_put(skey_ref); key_ref = make_key_ref(key, 1); @@ -194,10 +188,12 @@ static int proc_keys_show(struct seq_file *m, void *v) /* check whether the current task is allowed to view the key */ rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); if (rc < 0) - goto out; + return 0; now = ktime_get_real_seconds(); + rcu_read_lock(); + /* come up with a suitable timeout value */ expiry = READ_ONCE(key->expiry); if (expiry == 0) { @@ -236,7 +232,7 @@ static int proc_keys_show(struct seq_file *m, void *v) showflag(flags, 'i', KEY_FLAG_INVALIDATED), refcount_read(&key->usage), xbuf, - key_acl_to_perm(acl), + key->perm, from_kuid_munged(seq_user_ns(m), key->uid), from_kgid_munged(seq_user_ns(m), key->gid), key->type->name); @@ -247,7 +243,7 @@ static int proc_keys_show(struct seq_file *m, void *v) key->type->describe(key, m); seq_putc(m, '\n'); -out: + rcu_read_unlock(); return 0; } diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index aa3bfcadbc66..09541de31f2f 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -32,47 +32,6 @@ struct key_user root_key_user = { .uid = GLOBAL_ROOT_UID, }; -static struct key_acl user_reg_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .possessor_viewable = true, - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_WRITE | KEY_ACE_SEARCH), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), - } -}; - -static struct key_acl user_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .possessor_viewable = true, - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | - KEY_ACE_SEARCH | KEY_ACE_LINK), - KEY_OWNER_ACE(KEY_ACE__PERMS & ~(KEY_ACE_JOIN | KEY_ACE_SET_SECURITY)), - } -}; - -static struct key_acl session_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .possessor_viewable = true, - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN), - KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), - } -}; - -static struct key_acl thread_and_process_keyring_acl = { - .usage = REFCOUNT_INIT(1), - .possessor_viewable = true, - .nr_ace = 2, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~(KEY_ACE_JOIN | KEY_ACE_SET_SECURITY)), - KEY_OWNER_ACE(KEY_ACE_VIEW), - } -}; - /* * Get or create a user register keyring. */ @@ -92,8 +51,11 @@ static struct key *get_user_register(struct user_namespace *user_ns) if (!reg_keyring) { reg_keyring = keyring_alloc(".user_reg", user_ns->owner, INVALID_GID, - &init_cred, &user_reg_keyring_acl, - 0, NULL, NULL); + &init_cred, + KEY_POS_WRITE | KEY_POS_SEARCH | + KEY_USR_VIEW | KEY_USR_READ, + 0, + NULL, NULL); if (!IS_ERR(reg_keyring)) smp_store_release(&user_ns->user_keyring_register, reg_keyring); @@ -115,11 +77,14 @@ int look_up_user_keyrings(struct key **_user_keyring, const struct cred *cred = current_cred(); struct user_namespace *user_ns = current_user_ns(); struct key *reg_keyring, *uid_keyring, *session_keyring; + key_perm_t user_keyring_perm; key_ref_t uid_keyring_r, session_keyring_r; uid_t uid = from_kuid(user_ns, cred->user->uid); char buf[20]; int ret; + user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; + kenter("%u", uid); reg_keyring = get_user_register(user_ns); @@ -139,7 +104,7 @@ int look_up_user_keyrings(struct key **_user_keyring, kdebug("_uid %p", uid_keyring_r); if (uid_keyring_r == ERR_PTR(-EAGAIN)) { uid_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID, - cred, &user_keyring_acl, + cred, user_keyring_perm, KEY_ALLOC_UID_KEYRING | KEY_ALLOC_IN_QUOTA, NULL, reg_keyring); @@ -161,7 +126,7 @@ int look_up_user_keyrings(struct key **_user_keyring, kdebug("_uid_ses %p", session_keyring_r); if (session_keyring_r == ERR_PTR(-EAGAIN)) { session_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID, - cred, &user_keyring_acl, + cred, user_keyring_perm, KEY_ALLOC_UID_KEYRING | KEY_ALLOC_IN_QUOTA, NULL, NULL); @@ -261,7 +226,7 @@ int install_thread_keyring_to_cred(struct cred *new) return 0; keyring = keyring_alloc("_tid", new->uid, new->gid, new, - &thread_and_process_keyring_acl, + KEY_POS_ALL | KEY_USR_VIEW, KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); if (IS_ERR(keyring)) @@ -308,7 +273,7 @@ int install_process_keyring_to_cred(struct cred *new) return 0; keyring = keyring_alloc("_pid", new->uid, new->gid, new, - &thread_and_process_keyring_acl, + KEY_POS_ALL | KEY_USR_VIEW, KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); if (IS_ERR(keyring)) @@ -363,7 +328,8 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) flags = KEY_ALLOC_IN_QUOTA; keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, - &session_keyring_acl, flags, NULL, NULL); + KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, + flags, NULL, NULL); if (IS_ERR(keyring)) return PTR_ERR(keyring); } else { @@ -643,7 +609,7 @@ bool lookup_user_key_possessed(const struct key *key, * returned key reference. */ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, - unsigned int desired_perm) + key_perm_t perm) { struct keyring_search_context ctx = { .match_data.cmp = lookup_user_key_possessed, @@ -818,12 +784,12 @@ try_again: case -ERESTARTSYS: goto invalid_key; default: - if (desired_perm) + if (perm) goto invalid_key; case 0: break; } - } else if (desired_perm) { + } else if (perm) { ret = key_validate(key); if (ret < 0) goto invalid_key; @@ -835,11 +801,9 @@ try_again: goto invalid_key; /* check the permissions */ - if (desired_perm) { - ret = key_task_permission(key_ref, ctx.cred, desired_perm); - if (ret < 0) - goto invalid_key; - } + ret = key_task_permission(key_ref, ctx.cred, perm); + if (ret < 0) + goto invalid_key; key->last_used_at = ktime_get_real_seconds(); @@ -904,13 +868,13 @@ long join_session_keyring(const char *name) if (PTR_ERR(keyring) == -ENOKEY) { /* not found - try and create a new one */ keyring = keyring_alloc( - name, old->uid, old->gid, old, &joinable_keyring_acl, + name, old->uid, old->gid, old, + KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, KEY_ALLOC_IN_QUOTA, NULL, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } - goto no_perm_test; } else if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; @@ -919,12 +883,6 @@ long join_session_keyring(const char *name) goto error3; } - ret = key_task_permission(make_key_ref(keyring, false), old, - KEY_NEED_JOIN); - if (ret < 0) - goto error3; - -no_perm_test: /* we've got a keyring - now to install it */ ret = install_session_keyring_to_cred(new, keyring); if (ret < 0) diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 46c5187ce03f..7325f382dbf4 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -135,7 +135,8 @@ static int call_sbin_request_key(struct key *authkey, void *aux) cred = get_current_cred(); keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, - NULL, KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); + KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, + KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); put_cred(cred); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); @@ -366,11 +367,11 @@ static int construct_alloc_key(struct keyring_search_context *ctx, struct key *dest_keyring, unsigned long flags, struct key_user *user, - struct key_acl *acl, struct key **_key) { struct assoc_array_edit *edit = NULL; struct key *key; + key_perm_t perm; key_ref_t key_ref; int ret; @@ -380,9 +381,17 @@ static int construct_alloc_key(struct keyring_search_context *ctx, *_key = NULL; mutex_lock(&user->cons_lock); + perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; + perm |= KEY_USR_VIEW; + if (ctx->index_key.type->read) + perm |= KEY_POS_READ; + if (ctx->index_key.type == &key_type_keyring || + ctx->index_key.type->update) + perm |= KEY_POS_WRITE; + key = key_alloc(ctx->index_key.type, ctx->index_key.description, ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, - acl, flags, NULL); + perm, flags, NULL); if (IS_ERR(key)) goto alloc_failed; @@ -465,7 +474,6 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, const char *callout_info, size_t callout_len, void *aux, - struct key_acl *acl, struct key *dest_keyring, unsigned long flags) { @@ -488,7 +496,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, goto error_put_dest_keyring; } - ret = construct_alloc_key(ctx, dest_keyring, flags, user, acl, &key); + ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); key_user_put(user); if (ret == 0) { @@ -526,7 +534,6 @@ error: * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. - * @acl: The ACL to attach if a new key is created. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * @@ -554,7 +561,6 @@ 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) { @@ -629,7 +635,7 @@ struct key *request_key_and_link(struct key_type *type, goto error_free; key = construct_key_and_link(&ctx, callout_info, callout_len, - aux, acl, dest_keyring, flags); + aux, dest_keyring, flags); } error_free: @@ -672,7 +678,6 @@ EXPORT_SYMBOL(wait_for_key_construction); * @description: The searchable description of the key. * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @acl: The ACL to attach if a new key is created. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found, new keys are always allocated in the user's quota, @@ -685,8 +690,7 @@ EXPORT_SYMBOL(wait_for_key_construction); struct key *request_key_tag(struct key_type *type, const char *description, struct key_tag *domain_tag, - const char *callout_info, - struct key_acl *acl) + const char *callout_info) { struct key *key; size_t callout_len = 0; @@ -696,7 +700,7 @@ struct key *request_key_tag(struct key_type *type, callout_len = strlen(callout_info); key = request_key_and_link(type, description, domain_tag, callout_info, callout_len, - NULL, acl, NULL, KEY_ALLOC_IN_QUOTA); + NULL, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { @@ -716,7 +720,6 @@ EXPORT_SYMBOL(request_key_tag); * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. - * @acl: The ACL to attach if a new key is created. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found and new keys are always allocated in the user's quota. @@ -729,15 +732,14 @@ struct key *request_key_with_auxdata(struct key_type *type, struct key_tag *domain_tag, const void *callout_info, size_t callout_len, - void *aux, - struct key_acl *acl) + void *aux) { struct key *key; int ret; key = request_key_and_link(type, description, domain_tag, callout_info, callout_len, - aux, acl, NULL, KEY_ALLOC_IN_QUOTA); + aux, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 27e437d94b81..e73ec040e250 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -24,17 +24,6 @@ static void request_key_auth_revoke(struct key *); static void request_key_auth_destroy(struct key *); static long request_key_auth_read(const struct key *, char __user *, size_t); -static struct key_acl request_key_auth_acl = { - .usage = REFCOUNT_INIT(1), - .nr_ace = 2, - .possessor_viewable = true, - .aces = { - KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH | - KEY_ACE_LINK), - KEY_OWNER_ACE(KEY_ACE_VIEW), - } -}; - /* * The request-key authorisation key type definition. */ @@ -221,8 +210,8 @@ struct key *request_key_auth_new(struct key *target, const char *op, authkey = key_alloc(&key_type_request_key_auth, desc, cred->fsuid, cred->fsgid, cred, - &request_key_auth_acl, - KEY_ALLOC_NOT_IN_QUOTA, NULL); + KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_POS_LINK | + KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); if (IS_ERR(authkey)) { ret = PTR_ERR(authkey); goto error_free_rka; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4bef86ed463b..74dd46de01b6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6502,7 +6502,6 @@ static int selinux_key_permission(key_ref_t key_ref, { struct key *key; struct key_security_struct *ksec; - unsigned oldstyle_perm; u32 sid; /* if no specific permissions are requested, we skip the @@ -6511,26 +6510,13 @@ static int selinux_key_permission(key_ref_t key_ref, if (perm == 0) return 0; - oldstyle_perm = perm & (KEY_NEED_VIEW | KEY_NEED_READ | KEY_NEED_WRITE | - KEY_NEED_SEARCH | KEY_NEED_LINK); - if (perm & KEY_NEED_SETSEC) - oldstyle_perm |= OLD_KEY_NEED_SETATTR; - if (perm & KEY_NEED_INVAL) - oldstyle_perm |= KEY_NEED_SEARCH; - if (perm & KEY_NEED_REVOKE && !(perm & OLD_KEY_NEED_SETATTR)) - oldstyle_perm |= KEY_NEED_WRITE; - if (perm & KEY_NEED_JOIN) - oldstyle_perm |= KEY_NEED_SEARCH; - if (perm & KEY_NEED_CLEAR) - oldstyle_perm |= KEY_NEED_WRITE; - sid = cred_sid(cred); key = key_ref_to_ptr(key_ref); ksec = key->security; return avc_has_perm(&selinux_state, - sid, ksec->sid, SECCLASS_KEY, oldstyle_perm, NULL); + sid, ksec->sid, SECCLASS_KEY, perm, NULL); } static int selinux_key_getsecurity(struct key *key, char **_buffer) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 50c536cad85b..4c5e5a438f8b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4284,8 +4284,7 @@ static int smack_key_permission(key_ref_t key_ref, #endif if (perm & (KEY_NEED_READ | KEY_NEED_SEARCH | KEY_NEED_VIEW)) request |= MAY_READ; - if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETSEC | - KEY_NEED_INVAL | KEY_NEED_REVOKE | KEY_NEED_CLEAR)) + if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) request |= MAY_WRITE; rc = smk_access(tkp, keyp->security, request, &ad); rc = smk_bu_note("key access", tkp, keyp->security, request, rc); |