| /* Keyring handling |
| * |
| * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. |
| * Written by David Howells (dhowells@redhat.com) |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version |
| * 2 of the License, or (at your option) any later version. |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/init.h> |
| #include <linux/sched.h> |
| #include <linux/slab.h> |
| #include <linux/security.h> |
| #include <linux/seq_file.h> |
| #include <linux/err.h> |
| #include <keys/keyring-type.h> |
| #include <linux/uaccess.h> |
| #include "internal.h" |
| |
| #define rcu_dereference_locked_keyring(keyring) \ |
| (rcu_dereference_protected( \ |
| (keyring)->payload.subscriptions, \ |
| rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
| |
| #define KEY_LINK_FIXQUOTA 1UL |
| |
| /* |
| * When plumbing the depths of the key tree, this sets a hard limit |
| * set on how deep we're willing to go. |
| */ |
| #define KEYRING_SEARCH_MAX_DEPTH 6 |
| |
| /* |
| * We keep all named keyrings in a hash to speed looking them up. |
| */ |
| #define KEYRING_NAME_HASH_SIZE (1 << 5) |
| |
| static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; |
| static DEFINE_RWLOCK(keyring_name_lock); |
| |
| static inline unsigned keyring_hash(const char *desc) |
| { |
| unsigned bucket = 0; |
| |
| for (; *desc; desc++) |
| bucket += (unsigned char)*desc; |
| |
| return bucket & (KEYRING_NAME_HASH_SIZE - 1); |
| } |
| |
| /* |
| * The keyring key type definition. Keyrings are simply keys of this type and |
| * can be treated as ordinary keys in addition to having their own special |
| * operations. |
| */ |
| static int keyring_instantiate(struct key *keyring, |
| const void *data, size_t datalen); |
| static int keyring_match(const struct key *keyring, const void *criterion); |
| static void keyring_revoke(struct key *keyring); |
| static void keyring_destroy(struct key *keyring); |
| static void keyring_describe(const struct key *keyring, struct seq_file *m); |
| static long keyring_read(const struct key *keyring, |
| char __user *buffer, size_t buflen); |
| |
| struct key_type key_type_keyring = { |
| .name = "keyring", |
| .def_datalen = sizeof(struct keyring_list), |
| .instantiate = keyring_instantiate, |
| .match = keyring_match, |
| .revoke = keyring_revoke, |
| .destroy = keyring_destroy, |
| .describe = keyring_describe, |
| .read = keyring_read, |
| }; |
| EXPORT_SYMBOL(key_type_keyring); |
| |
| /* |
| * Semaphore to serialise link/link calls to prevent two link calls in parallel |
| * introducing a cycle. |
| */ |
| static DECLARE_RWSEM(keyring_serialise_link_sem); |
| |
| /* |
| * Publish the name of a keyring so that it can be found by name (if it has |
| * one). |
| */ |
| static void keyring_publish_name(struct key *keyring) |
| { |
| int bucket; |
| |
| if (keyring->description) { |
| bucket = keyring_hash(keyring->description); |
| |
| write_lock(&keyring_name_lock); |
| |
| if (!keyring_name_hash[bucket].next) |
| INIT_LIST_HEAD(&keyring_name_hash[bucket]); |
| |
| list_add_tail(&keyring->type_data.link, |
| &keyring_name_hash[bucket]); |
| |
| write_unlock(&keyring_name_lock); |
| } |
| } |
| |
| /* |
| * Initialise a keyring. |
| * |
| * Returns 0 on success, -EINVAL if given any data. |
| */ |
| static int keyring_instantiate(struct key *keyring, |
| const void *data, size_t datalen) |
| { |
| int ret; |
| |
| ret = -EINVAL; |
| if (datalen == 0) { |
| /* make the keyring available by name if it has one */ |
| keyring_publish_name(keyring); |
| ret = 0; |
| } |
| |
| return ret; |
| } |
| |
| /* |
| * Match keyrings on their name |
| */ |
| static int keyring_match(const struct key *keyring, const void *description) |
| { |
| return keyring->description && |
| strcmp(keyring->description, description) == 0; |
| } |
| |
| /* |
| * Clean up a keyring when it is destroyed. Unpublish its name if it had one |
| * and dispose of its data. |
| */ |
| static void keyring_destroy(struct key *keyring) |
| { |
| struct keyring_list *klist; |
| int loop; |
| |
| if (keyring->description) { |
| write_lock(&keyring_name_lock); |
| |
| if (keyring->type_data.link.next != NULL && |
| !list_empty(&keyring->type_data.link)) |
| list_del(&keyring->type_data.link); |
| |
| write_unlock(&keyring_name_lock); |
| } |
| |
| klist = rcu_dereference_check(keyring->payload.subscriptions, |
| rcu_read_lock_held() || |
| atomic_read(&keyring->usage) == 0); |
| if (klist) { |
| for (loop = klist->nkeys - 1; loop >= 0; loop--) |
| key_put(klist->keys[loop]); |
| kfree(klist); |
| } |
| } |
| |
| /* |
| * Describe a keyring for /proc. |
| */ |
| static void keyring_describe(const struct key *keyring, struct seq_file *m) |
| { |
| struct keyring_list *klist; |
| |
| if (keyring->description) |
| seq_puts(m, keyring->description); |
| else |
| seq_puts(m, "[anon]"); |
| |
| rcu_read_lock(); |
| klist = rcu_dereference(keyring->payload.subscriptions); |
| if (klist) |
| seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); |
| else |
| seq_puts(m, ": empty"); |
| rcu_read_unlock(); |
| } |
| |
| /* |
| * Read a list of key IDs from the keyring's contents in binary form |
| * |
| * The keyring's semaphore is read-locked by the caller. |
| */ |
| static long keyring_read(const struct key *keyring, |
| char __user *buffer, size_t buflen) |
| { |
| struct keyring_list *klist; |
| struct key *key; |
| size_t qty, tmp; |
| int loop, ret; |
| |
| ret = 0; |
| klist = rcu_dereference_locked_keyring(keyring); |
| if (klist) { |
| /* calculate how much data we could return */ |
| qty = klist->nkeys * sizeof(key_serial_t); |
| |
| if (buffer && buflen > 0) { |
| if (buflen > qty) |
| buflen = qty; |
| |
| /* copy the IDs of the subscribed keys into the |
| * buffer */ |
| ret = -EFAULT; |
| |
| for (loop = 0; loop < klist->nkeys; loop++) { |
| key = klist->keys[loop]; |
| |
| tmp = sizeof(key_serial_t); |
| if (tmp > buflen) |
| tmp = buflen; |
| |
| if (copy_to_user(buffer, |
| &key->serial, |
| tmp) != 0) |
| goto error; |
| |
| buflen -= tmp; |
| if (buflen == 0) |
| break; |
| buffer += tmp; |
| } |
| } |
| |
| ret = qty; |
| } |
| |
| error: |
| return ret; |
| } |
| |
| /* |
| * Allocate a keyring and link into the destination keyring. |
| */ |
| struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
| const struct cred *cred, unsigned long flags, |
| struct key *dest) |
| { |
| struct key *keyring; |
| int ret; |
| |
| keyring = key_alloc(&key_type_keyring, description, |
| uid, gid, cred, |
| (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, |
| flags); |
| |
| if (!IS_ERR(keyring)) { |
| ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); |
| if (ret < 0) { |
| key_put(keyring); |
| keyring = ERR_PTR(ret); |
| } |
| } |
| |
| return keyring; |
| } |
| |
| /** |
| * keyring_search_aux - Search a keyring tree for a key matching some criteria |
| * @keyring_ref: A pointer to the keyring with possession indicator. |
| * @cred: The credentials to use for permissions checks. |
| * @type: The type of key to search for. |
| * @description: Parameter for @match. |
| * @match: Function to rule on whether or not a key is the one required. |
| * |
| * Search the supplied keyring tree for a key that matches the criteria given. |
| * The root keyring and any linked keyrings must grant Search permission to the |
| * caller to be searchable and keys can only be found if they too grant Search |
| * to the caller. The possession flag on the root keyring pointer controls use |
| * of the possessor bits in permissions checking of the entire tree. In |
| * addition, the LSM gets to forbid keyring searches and key matches. |
| * |
| * The search is performed as a breadth-then-depth search up to the prescribed |
| * limit (KEYRING_SEARCH_MAX_DEPTH). |
| * |
| * Keys are matched to the type provided and are then filtered by the match |
| * function, which is given the description to use in any way it sees fit. The |
| * match function may use any attributes of a key that it wishes to to |
| * determine the match. Normally the match function from the key type would be |
| * used. |
| * |
| * RCU is used to prevent the keyring key lists from disappearing without the |
| * need to take lots of locks. |
| * |
| * Returns a pointer to the found key and increments the key usage count if |
| * successful; -EAGAIN if no matching keys were found, or if expired or revoked |
| * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the |
| * specified keyring wasn't a keyring. |
| * |
| * In the case of a successful return, the possession attribute from |
| * @keyring_ref is propagated to the returned key reference. |
| */ |
| key_ref_t keyring_search_aux(key_ref_t keyring_ref, |
| const struct cred *cred, |
| struct key_type *type, |
| const void *description, |
| key_match_func_t match) |
| { |
| struct { |
| struct keyring_list *keylist; |
| int kix; |
| } stack[KEYRING_SEARCH_MAX_DEPTH]; |
| |
| struct keyring_list *keylist; |
| struct timespec now; |
| unsigned long possessed, kflags; |
| struct key *keyring, *key; |
| key_ref_t key_ref; |
| long err; |
| int sp, kix; |
| |
| keyring = key_ref_to_ptr(keyring_ref); |
| possessed = is_key_possessed(keyring_ref); |
| key_check(keyring); |
| |
| /* top keyring must have search permission to begin the search */ |
| err = key_task_permission(keyring_ref, cred, KEY_SEARCH); |
| if (err < 0) { |
| key_ref = ERR_PTR(err); |
| goto error; |
| } |
| |
| key_ref = ERR_PTR(-ENOTDIR); |
| if (keyring->type != &key_type_keyring) |
| goto error; |
| |
| rcu_read_lock(); |
| |
| now = current_kernel_time(); |
| err = -EAGAIN; |
| sp = 0; |
| |
| /* firstly we should check to see if this top-level keyring is what we |
| * are looking for */ |
| key_ref = ERR_PTR(-EAGAIN); |
| kflags = keyring->flags; |
| if (keyring->type == type && match(keyring, description)) { |
| key = keyring; |
| |
| /* check it isn't negative and hasn't expired or been |
| * revoked */ |
| if (kflags & (1 << KEY_FLAG_REVOKED)) |
| goto error_2; |
| if (key->expiry && now.tv_sec >= key->expiry) |
| goto error_2; |
| key_ref = ERR_PTR(-ENOKEY); |
| if (kflags & (1 << KEY_FLAG_NEGATIVE)) |
| goto error_2; |
| goto found; |
| } |
| |
| /* otherwise, the top keyring must not be revoked, expired, or |
| * negatively instantiated if we are to search it */ |
| key_ref = ERR_PTR(-EAGAIN); |
| if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || |
| (keyring->expiry && now.tv_sec >= keyring->expiry)) |
| goto error_2; |
| |
| /* start processing a new keyring */ |
| descend: |
| if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
| goto not_this_keyring; |
| |
| keylist = rcu_dereference(keyring->payload.subscriptions); |
| if (!keylist) |
| goto not_this_keyring; |
| |
| /* iterate through the keys in this keyring first */ |
| for (kix = 0; kix < keylist->nkeys; kix++) { |
| key = keylist->keys[kix]; |
| kflags = key->flags; |
| |
| /* ignore keys not of this type */ |
| if (key->type != type) |
| continue; |
| |
| /* skip revoked keys and expired keys */ |
| if (kflags & (1 << KEY_FLAG_REVOKED)) |
| continue; |
| |
| if (key->expiry && now.tv_sec >= key->expiry) |
| continue; |
| |
| /* keys that don't match */ |
| if (!match(key, description)) |
| continue; |
| |
| /* key must have search permissions */ |
| if (key_task_permission(make_key_ref(key, possessed), |
| cred, KEY_SEARCH) < 0) |
| continue; |
| |
| /* we set a different error code if we pass a negative key */ |
| if (kflags & (1 << KEY_FLAG_NEGATIVE)) { |
| err = -ENOKEY; |
| continue; |
| } |
| |
| goto found; |
| } |
| |
| /* search through the keyrings nested in this one */ |
| kix = 0; |
| ascend: |
| for (; kix < keylist->nkeys; kix++) { |
| key = keylist->keys[kix]; |
| if (key->type != &key_type_keyring) |
| continue; |
| |
| /* recursively search nested keyrings |
| * - only search keyrings for which we have search permission |
| */ |
| if (sp >= KEYRING_SEARCH_MAX_DEPTH) |
| continue; |
| |
| if (key_task_permission(make_key_ref(key, possessed), |
| cred, KEY_SEARCH) < 0) |
| continue; |
| |
| /* stack the current position */ |
| stack[sp].keylist = keylist; |
| stack[sp].kix = kix; |
| sp++; |
| |
| /* begin again with the new keyring */ |
| keyring = key; |
| goto descend; |
| } |
| |
| /* the keyring we're looking at was disqualified or didn't contain a |
| * matching key */ |
| not_this_keyring: |
| if (sp > 0) { |
| /* resume the processing of a keyring higher up in the tree */ |
| sp--; |
| keylist = stack[sp].keylist; |
| kix = stack[sp].kix + 1; |
| goto ascend; |
| } |
| |
| key_ref = ERR_PTR(err); |
| goto error_2; |
| |
| /* we found a viable match */ |
| found: |
| atomic_inc(&key->usage); |
| key_check(key); |
| key_ref = make_key_ref(key, possessed); |
| error_2: |
| rcu_read_unlock(); |
| error: |
| return key_ref; |
| } |
| |
| /** |
| * keyring_search - Search the supplied keyring tree for a matching key |
| * @keyring: The root of the keyring tree to be searched. |
| * @type: The type of keyring we want to find. |
| * @description: The name of the keyring we want to find. |
| * |
| * As keyring_search_aux() above, but using the current task's credentials and |
| * type's default matching function. |
| */ |
| key_ref_t keyring_search(key_ref_t keyring, |
| struct key_type *type, |
| const char *description) |
| { |
| if (!type->match) |
| return ERR_PTR(-ENOKEY); |
| |
| return keyring_search_aux(keyring, current->cred, |
| type, description, type->match); |
| } |
| EXPORT_SYMBOL(keyring_search); |
| |
| /* |
| * Search the given keyring only (no recursion). |
| * |
| * The caller must guarantee that the keyring is a keyring and that the |
| * permission is granted to search the keyring as no check is made here. |
| * |
| * RCU is used to make it unnecessary to lock the keyring key list here. |
| * |
| * Returns a pointer to the found key with usage count incremented if |
| * successful and returns -ENOKEY if not found. Revoked keys and keys not |
| * providing the requested permission are skipped over. |
| * |
| * If successful, the possession indicator is propagated from the keyring ref |
| * to the returned key reference. |
| */ |
| key_ref_t __keyring_search_one(key_ref_t keyring_ref, |
| const struct key_type *ktype, |
| const char *description, |
| key_perm_t perm) |
| { |
| struct keyring_list *klist; |
| unsigned long possessed; |
| struct key *keyring, *key; |
| int loop; |
| |
| keyring = key_ref_to_ptr(keyring_ref); |
| possessed = is_key_possessed(keyring_ref); |
| |
| rcu_read_lock(); |
| |
| klist = rcu_dereference(keyring->payload.subscriptions); |
| if (klist) { |
| for (loop = 0; loop < klist->nkeys; loop++) { |
| key = klist->keys[loop]; |
| |
| if (key->type == ktype && |
| (!key->type->match || |
| key->type->match(key, description)) && |
| key_permission(make_key_ref(key, possessed), |
| perm) == 0 && |
| !test_bit(KEY_FLAG_REVOKED, &key->flags) |
| ) |
| goto found; |
| } |
| } |
| |
| rcu_read_unlock(); |
| return ERR_PTR(-ENOKEY); |
| |
| found: |
| atomic_inc(&key->usage); |
| rcu_read_unlock(); |
| return make_key_ref(key, possessed); |
| } |
| |
| /* |
| * Find a keyring with the specified name. |
| * |
| * All named keyrings in the current user namespace are searched, provided they |
| * grant Search permission directly to the caller (unless this check is |
| * skipped). Keyrings whose usage points have reached zero or who have been |
| * revoked are skipped. |
| * |
| * 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. |
| */ |
| struct key *find_keyring_by_name(const char *name, bool skip_perm_check) |
| { |
| struct key *keyring; |
| int bucket; |
| |
| if (!name) |
| return ERR_PTR(-EINVAL); |
| |
| bucket = keyring_hash(name); |
| |
| read_lock(&keyring_name_lock); |
| |
| if (keyring_name_hash[bucket].next) { |
| /* search this hash bucket for a keyring with a matching name |
| * that's readable and that hasn't been revoked */ |
| list_for_each_entry(keyring, |
| &keyring_name_hash[bucket], |
| type_data.link |
| ) { |
| if (keyring->user->user_ns != current_user_ns()) |
| continue; |
| |
| if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
| continue; |
| |
| if (strcmp(keyring->description, name) != 0) |
| continue; |
| |
| if (!skip_perm_check && |
| key_permission(make_key_ref(keyring, 0), |
| KEY_SEARCH) < 0) |
| continue; |
| |
| /* we've got a match but we might end up racing with |
| * key_cleanup() if the keyring is currently 'dead' |
| * (ie. it has a zero usage count) */ |
| if (!atomic_inc_not_zero(&keyring->usage)) |
| continue; |
| goto out; |
| } |
| } |
| |
| keyring = ERR_PTR(-ENOKEY); |
| out: |
| read_unlock(&keyring_name_lock); |
| return keyring; |
| } |
| |
| /* |
| * See if a cycle will will be created by inserting acyclic tree B in acyclic |
| * tree A at the topmost level (ie: as a direct child of A). |
| * |
| * Since we are adding B to A at the top level, checking for cycles should just |
| * be a matter of seeing if node A is somewhere in tree B. |
| */ |
| static int keyring_detect_cycle(struct key *A, struct key *B) |
| { |
| struct { |
| struct keyring_list *keylist; |
| int kix; |
| } stack[KEYRING_SEARCH_MAX_DEPTH]; |
| |
| struct keyring_list *keylist; |
| struct key *subtree, *key; |
| int sp, kix, ret; |
| |
| rcu_read_lock(); |
| |
| ret = -EDEADLK; |
| if (A == B) |
| goto cycle_detected; |
| |
| subtree = B; |
| sp = 0; |
| |
| /* start processing a new keyring */ |
| descend: |
| if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) |
| goto not_this_keyring; |
| |
| keylist = rcu_dereference(subtree->payload.subscriptions); |
| if (!keylist) |
| goto not_this_keyring; |
| kix = 0; |
| |
| ascend: |
| /* iterate through the remaining keys in this keyring */ |
| for (; kix < keylist->nkeys; kix++) { |
| key = keylist->keys[kix]; |
| |
| if (key == A) |
| goto cycle_detected; |
| |
| /* recursively check nested keyrings */ |
| if (key->type == &key_type_keyring) { |
| if (sp >= KEYRING_SEARCH_MAX_DEPTH) |
| goto too_deep; |
| |
| /* stack the current position */ |
| stack[sp].keylist = keylist; |
| stack[sp].kix = kix; |
| sp++; |
| |
| /* begin again with the new keyring */ |
| subtree = key; |
| goto descend; |
| } |
| } |
| |
| /* the keyring we're looking at was disqualified or didn't contain a |
| * matching key */ |
| not_this_keyring: |
| if (sp > 0) { |
| /* resume the checking of a keyring higher up in the tree */ |
| sp--; |
| keylist = stack[sp].keylist; |
| kix = stack[sp].kix + 1; |
| goto ascend; |
| } |
| |
| ret = 0; /* no cycles detected */ |
| |
| error: |
| rcu_read_unlock(); |
| return ret; |
| |
| too_deep: |
| ret = -ELOOP; |
| goto error; |
| |
| cycle_detected: |
| ret = -EDEADLK; |
| goto error; |
| } |
| |
| /* |
| * Dispose of a keyring list after the RCU grace period, freeing the unlinked |
| * key |
| */ |
| static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) |
| { |
| struct keyring_list *klist = |
| container_of(rcu, struct keyring_list, rcu); |
| |
| if (klist->delkey != USHRT_MAX) |
| key_put(klist->keys[klist->delkey]); |
| kfree(klist); |
| } |
| |
| /* |
| * Preallocate memory so that a key can be linked into to a keyring. |
| */ |
| int __key_link_begin(struct key *keyring, const struct key_type *type, |
| const char *description, unsigned long *_prealloc) |
| __acquires(&keyring->sem) |
| { |
| struct keyring_list *klist, *nklist; |
| unsigned long prealloc; |
| unsigned max; |
| size_t size; |
| int loop, ret; |
| |
| kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
| |
| if (keyring->type != &key_type_keyring) |
| return -ENOTDIR; |
| |
| down_write(&keyring->sem); |
| |
| ret = -EKEYREVOKED; |
| if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
| goto error_krsem; |
| |
| /* serialise link/link calls to prevent parallel calls causing a cycle |
| * when linking two keyring in opposite orders */ |
| if (type == &key_type_keyring) |
| down_write(&keyring_serialise_link_sem); |
| |
| klist = rcu_dereference_locked_keyring(keyring); |
| |
| /* see if there's a matching key we can displace */ |
| if (klist && klist->nkeys > 0) { |
| for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
| if (klist->keys[loop]->type == type && |
| strcmp(klist->keys[loop]->description, |
| description) == 0 |
| ) { |
| /* found a match - we'll replace this one with |
| * the new key */ |
| size = sizeof(struct key *) * klist->maxkeys; |
| size += sizeof(*klist); |
| BUG_ON(size > PAGE_SIZE); |
| |
| ret = -ENOMEM; |
| nklist = kmemdup(klist, size, GFP_KERNEL); |
| if (!nklist) |
| goto error_sem; |
| |
| /* note replacement slot */ |
| klist->delkey = nklist->delkey = loop; |
| prealloc = (unsigned long)nklist; |
| goto done; |
| } |
| } |
| } |
| |
| /* check that we aren't going to overrun the user's quota */ |
| ret = key_payload_reserve(keyring, |
| keyring->datalen + KEYQUOTA_LINK_BYTES); |
| if (ret < 0) |
| goto error_sem; |
| |
| if (klist && klist->nkeys < klist->maxkeys) { |
| /* there's sufficient slack space to append directly */ |
| nklist = NULL; |
| prealloc = KEY_LINK_FIXQUOTA; |
| } else { |
| /* grow the key list */ |
| max = 4; |
| if (klist) |
| max += klist->maxkeys; |
| |
| ret = -ENFILE; |
| if (max > USHRT_MAX - 1) |
| goto error_quota; |
| size = sizeof(*klist) + sizeof(struct key *) * max; |
| if (size > PAGE_SIZE) |
| goto error_quota; |
| |
| ret = -ENOMEM; |
| nklist = kmalloc(size, GFP_KERNEL); |
| if (!nklist) |
| goto error_quota; |
| |
| nklist->maxkeys = max; |
| if (klist) { |
| memcpy(nklist->keys, klist->keys, |
| sizeof(struct key *) * klist->nkeys); |
| nklist->delkey = klist->nkeys; |
| nklist->nkeys = klist->nkeys + 1; |
| klist->delkey = USHRT_MAX; |
| } else { |
| nklist->nkeys = 1; |
| nklist->delkey = 0; |
| } |
| |
| /* add the key into the new space */ |
| nklist->keys[nklist->delkey] = NULL; |
| } |
| |
| prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; |
| done: |
| *_prealloc = prealloc; |
| kleave(" = 0"); |
| return 0; |
| |
| error_quota: |
| /* undo the quota changes */ |
| key_payload_reserve(keyring, |
| keyring->datalen - KEYQUOTA_LINK_BYTES); |
| error_sem: |
| if (type == &key_type_keyring) |
| up_write(&keyring_serialise_link_sem); |
| error_krsem: |
| up_write(&keyring->sem); |
| kleave(" = %d", ret); |
| return ret; |
| } |
| |
| /* |
| * Check already instantiated keys aren't going to be a problem. |
| * |
| * The caller must have called __key_link_begin(). Don't need to call this for |
| * keys that were created since __key_link_begin() was called. |
| */ |
| int __key_link_check_live_key(struct key *keyring, struct key *key) |
| { |
| if (key->type == &key_type_keyring) |
| /* check that we aren't going to create a cycle by linking one |
| * keyring to another */ |
| return keyring_detect_cycle(keyring, key); |
| return 0; |
| } |
| |
| /* |
| * Link a key into to a keyring. |
| * |
| * Must be called with __key_link_begin() having being called. Discards any |
| * already extant link to matching key if there is one, so that each keyring |
| * holds at most one link to any given key of a particular type+description |
| * combination. |
| */ |
| void __key_link(struct key *keyring, struct key *key, |
| unsigned long *_prealloc) |
| { |
| struct keyring_list *klist, *nklist; |
| |
| nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
| *_prealloc = 0; |
| |
| kenter("%d,%d,%p", keyring->serial, key->serial, nklist); |
| |
| klist = rcu_dereference_protected(keyring->payload.subscriptions, |
| rwsem_is_locked(&keyring->sem)); |
| |
| atomic_inc(&key->usage); |
| |
| /* there's a matching key we can displace or an empty slot in a newly |
| * allocated list we can fill */ |
| if (nklist) { |
| kdebug("replace %hu/%hu/%hu", |
| nklist->delkey, nklist->nkeys, nklist->maxkeys); |
| |
| nklist->keys[nklist->delkey] = key; |
| |
| rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
| |
| /* dispose of the old keyring list and, if there was one, the |
| * displaced key */ |
| if (klist) { |
| kdebug("dispose %hu/%hu/%hu", |
| klist->delkey, klist->nkeys, klist->maxkeys); |
| call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
| } |
| } else { |
| /* there's sufficient slack space to append directly */ |
| klist->keys[klist->nkeys] = key; |
| smp_wmb(); |
| klist->nkeys++; |
| } |
| } |
| |
| /* |
| * Finish linking a key into to a keyring. |
| * |
| * Must be called with __key_link_begin() having being called. |
| */ |
| void __key_link_end(struct key *keyring, struct key_type *type, |
| unsigned long prealloc) |
| __releases(&keyring->sem) |
| { |
| BUG_ON(type == NULL); |
| BUG_ON(type->name == NULL); |
| kenter("%d,%s,%lx", keyring->serial, type->name, prealloc); |
| |
| if (type == &key_type_keyring) |
| up_write(&keyring_serialise_link_sem); |
| |
| if (prealloc) { |
| if (prealloc & KEY_LINK_FIXQUOTA) |
| key_payload_reserve(keyring, |
| keyring->datalen - |
| KEYQUOTA_LINK_BYTES); |
| kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA)); |
| } |
| up_write(&keyring->sem); |
| } |
| |
| /** |
| * key_link - Link a key to a keyring |
| * @keyring: The keyring to make the link in. |
| * @key: The key to link to. |
| * |
| * Make a link in a keyring to a key, such that the keyring holds a reference |
| * on that key and the key can potentially be found by searching that keyring. |
| * |
| * This function will write-lock the keyring's semaphore and will consume some |
| * of the user's key data quota to hold the link. |
| * |
| * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, |
| * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is |
| * full, -EDQUOT if there is insufficient key data quota remaining to add |
| * another link or -ENOMEM if there's insufficient memory. |
| * |
| * It is assumed that the caller has checked that it is permitted for a link to |
| * be made (the keyring should have Write permission and the key Link |
| * permission). |
| */ |
| int key_link(struct key *keyring, struct key *key) |
| { |
| unsigned long prealloc; |
| int ret; |
| |
| key_check(keyring); |
| key_check(key); |
| |
| ret = __key_link_begin(keyring, key->type, key->description, &prealloc); |
| if (ret == 0) { |
| ret = __key_link_check_live_key(keyring, key); |
| if (ret == 0) |
| __key_link(keyring, key, &prealloc); |
| __key_link_end(keyring, key->type, prealloc); |
| } |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(key_link); |
| |
| /** |
| * key_unlink - Unlink the first link to a key from a keyring. |
| * @keyring: The keyring to remove the link from. |
| * @key: The key the link is to. |
| * |
| * Remove a link from a keyring to a key. |
| * |
| * This function will write-lock the keyring's semaphore. |
| * |
| * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if |
| * the key isn't linked to by the keyring or -ENOMEM if there's insufficient |
| * memory. |
| * |
| * It is assumed that the caller has checked that it is permitted for a link to |
| * be removed (the keyring should have Write permission; no permissions are |
| * required on the key). |
| */ |
| int key_unlink(struct key *keyring, struct key *key) |
| { |
| struct keyring_list *klist, *nklist; |
| int loop, ret; |
| |
| key_check(keyring); |
| key_check(key); |
| |
| ret = -ENOTDIR; |
| if (keyring->type != &key_type_keyring) |
| goto error; |
| |
| down_write(&keyring->sem); |
| |
| klist = rcu_dereference_locked_keyring(keyring); |
| if (klist) { |
| /* search the keyring for the key */ |
| for (loop = 0; loop < klist->nkeys; loop++) |
| if (klist->keys[loop] == key) |
| goto key_is_present; |
| } |
| |
| up_write(&keyring->sem); |
| ret = -ENOENT; |
| goto error; |
| |
| key_is_present: |
| /* we need to copy the key list for RCU purposes */ |
| nklist = kmalloc(sizeof(*klist) + |
| sizeof(struct key *) * klist->maxkeys, |
| GFP_KERNEL); |
| if (!nklist) |
| goto nomem; |
| nklist->maxkeys = klist->maxkeys; |
| nklist->nkeys = klist->nkeys - 1; |
| |
| if (loop > 0) |
| memcpy(&nklist->keys[0], |
| &klist->keys[0], |
| loop * sizeof(struct key *)); |
| |
| if (loop < nklist->nkeys) |
| memcpy(&nklist->keys[loop], |
| &klist->keys[loop + 1], |
| (nklist->nkeys - loop) * sizeof(struct key *)); |
| |
| /* adjust the user's quota */ |
| key_payload_reserve(keyring, |
| keyring->datalen - KEYQUOTA_LINK_BYTES); |
| |
| rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
| |
| up_write(&keyring->sem); |
| |
| /* schedule for later cleanup */ |
| klist->delkey = loop; |
| call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
| |
| ret = 0; |
| |
| error: |
| return ret; |
| nomem: |
| ret = -ENOMEM; |
| up_write(&keyring->sem); |
| goto error; |
| } |
| EXPORT_SYMBOL(key_unlink); |
| |
| /* |
| * Dispose of a keyring list after the RCU grace period, releasing the keys it |
| * links to. |
| */ |
| static void keyring_clear_rcu_disposal(struct rcu_head *rcu) |
| { |
| struct keyring_list *klist; |
| int loop; |
| |
| klist = container_of(rcu, struct keyring_list, rcu); |
| |
| for (loop = klist->nkeys - 1; loop >= 0; loop--) |
| key_put(klist->keys[loop]); |
| |
| kfree(klist); |
| } |
| |
| /** |
| * keyring_clear - Clear a keyring |
| * @keyring: The keyring to clear. |
| * |
| * Clear the contents of the specified keyring. |
| * |
| * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring. |
| */ |
| int keyring_clear(struct key *keyring) |
| { |
| struct keyring_list *klist; |
| int ret; |
| |
| ret = -ENOTDIR; |
| if (keyring->type == &key_type_keyring) { |
| /* detach the pointer block with the locks held */ |
| down_write(&keyring->sem); |
| |
| klist = rcu_dereference_locked_keyring(keyring); |
| if (klist) { |
| /* adjust the quota */ |
| key_payload_reserve(keyring, |
| sizeof(struct keyring_list)); |
| |
| rcu_assign_pointer(keyring->payload.subscriptions, |
| NULL); |
| } |
| |
| up_write(&keyring->sem); |
| |
| /* free the keys after the locks have been dropped */ |
| if (klist) |
| call_rcu(&klist->rcu, keyring_clear_rcu_disposal); |
| |
| ret = 0; |
| } |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(keyring_clear); |
| |
| /* |
| * Dispose of the links from a revoked keyring. |
| * |
| * This is called with the key sem write-locked. |
| */ |
| static void keyring_revoke(struct key *keyring) |
| { |
| struct keyring_list *klist; |
| |
| klist = rcu_dereference_locked_keyring(keyring); |
| |
| /* adjust the quota */ |
| key_payload_reserve(keyring, 0); |
| |
| if (klist) { |
| rcu_assign_pointer(keyring->payload.subscriptions, NULL); |
| call_rcu(&klist->rcu, keyring_clear_rcu_disposal); |
| } |
| } |
| |
| /* |
| * Determine whether a key is dead. |
| */ |
| static bool key_is_dead(struct key *key, time_t limit) |
| { |
| return test_bit(KEY_FLAG_DEAD, &key->flags) || |
| (key->expiry > 0 && key->expiry <= limit); |
| } |
| |
| /* |
| * Collect garbage from the contents of a keyring, replacing the old list with |
| * a new one with the pointers all shuffled down. |
| * |
| * Dead keys are classed as oned that are flagged as being dead or are revoked, |
| * expired or negative keys that were revoked or expired before the specified |
| * limit. |
| */ |
| void keyring_gc(struct key *keyring, time_t limit) |
| { |
| struct keyring_list *klist, *new; |
| struct key *key; |
| int loop, keep, max; |
| |
| kenter("{%x,%s}", key_serial(keyring), keyring->description); |
| |
| down_write(&keyring->sem); |
| |
| klist = rcu_dereference_locked_keyring(keyring); |
| if (!klist) |
| goto no_klist; |
| |
| /* work out how many subscriptions we're keeping */ |
| keep = 0; |
| for (loop = klist->nkeys - 1; loop >= 0; loop--) |
| if (!key_is_dead(klist->keys[loop], limit)) |
| keep++; |
| |
| if (keep == klist->nkeys) |
| goto just_return; |
| |
| /* allocate a new keyring payload */ |
| max = roundup(keep, 4); |
| new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), |
| GFP_KERNEL); |
| if (!new) |
| goto nomem; |
| new->maxkeys = max; |
| new->nkeys = 0; |
| new->delkey = 0; |
| |
| /* install the live keys |
| * - must take care as expired keys may be updated back to life |
| */ |
| keep = 0; |
| for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
| key = klist->keys[loop]; |
| if (!key_is_dead(key, limit)) { |
| if (keep >= max) |
| goto discard_new; |
| new->keys[keep++] = key_get(key); |
| } |
| } |
| new->nkeys = keep; |
| |
| /* adjust the quota */ |
| key_payload_reserve(keyring, |
| sizeof(struct keyring_list) + |
| KEYQUOTA_LINK_BYTES * keep); |
| |
| if (keep == 0) { |
| rcu_assign_pointer(keyring->payload.subscriptions, NULL); |
| kfree(new); |
| } else { |
| rcu_assign_pointer(keyring->payload.subscriptions, new); |
| } |
| |
| up_write(&keyring->sem); |
| |
| call_rcu(&klist->rcu, keyring_clear_rcu_disposal); |
| kleave(" [yes]"); |
| return; |
| |
| discard_new: |
| new->nkeys = keep; |
| keyring_clear_rcu_disposal(&new->rcu); |
| up_write(&keyring->sem); |
| kleave(" [discard]"); |
| return; |
| |
| just_return: |
| up_write(&keyring->sem); |
| kleave(" [no dead]"); |
| return; |
| |
| no_klist: |
| up_write(&keyring->sem); |
| kleave(" [no_klist]"); |
| return; |
| |
| nomem: |
| up_write(&keyring->sem); |
| kleave(" [oom]"); |
| } |