diff options
Diffstat (limited to 'ANDROID_3.4.5/security/keys/keyring.c')
-rw-r--r-- | ANDROID_3.4.5/security/keys/keyring.c | 1232 |
1 files changed, 0 insertions, 1232 deletions
diff --git a/ANDROID_3.4.5/security/keys/keyring.c b/ANDROID_3.4.5/security/keys/keyring.c deleted file mode 100644 index d605f752..00000000 --- a/ANDROID_3.4.5/security/keys/keyring.c +++ /dev/null @@ -1,1232 +0,0 @@ -/* 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, - 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]"); - - if (key_is_instantiated(keyring)) { - 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. - * @no_state_check: Don't check if a matching key is bad - * - * 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, - bool no_state_check) -{ - 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, nkeys, 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; - if (no_state_check) - goto found; - - /* 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(key->type_data.reject_error); - 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 */ - nkeys = keylist->nkeys; - smp_rmb(); - for (kix = 0; kix < 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 (!no_state_check) { - 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; - - if (no_state_check) - goto found; - - /* we set a different error code if we pass a negative key */ - if (kflags & (1 << KEY_FLAG_NEGATIVE)) { - err = key->type_data.reject_error; - continue; - } - - goto found; - } - - /* search through the keyrings nested in this one */ - kix = 0; -ascend: - nkeys = keylist->nkeys; - smp_rmb(); - for (; kix < 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, false); -} -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 nkeys, 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) { - nkeys = klist->nkeys; - smp_rmb(); - for (loop = 0; loop < 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, nkeys, 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 */ - nkeys = keylist->nkeys; - smp_rmb(); - for (; kix < 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_locked_keyring(keyring); - - 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]"); -} |