]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - security/keys/keyring.c
Merge branch 'next' into for-linus
[linux-3.10.git] / security / keys / keyring.c
index 0639396dd441eabdc27418b66df7673a749419e8..a06ffab38568809f5187970261888d6a9e673f18 100644 (file)
@@ -1,6 +1,6 @@
-/* keyring.c: keyring handling
+/* Keyring handling
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * 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
 #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 <asm/uaccess.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
+ * 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
+ * We keep all named keyrings in a hash to speed looking them up.
  */
 #define KEYRING_NAME_HASH_SIZE (1 << 5)
 
@@ -37,18 +46,20 @@ static inline unsigned keyring_hash(const char *desc)
        unsigned bucket = 0;
 
        for (; *desc; desc++)
-               bucket += (unsigned char) *desc;
+               bucket += (unsigned char)*desc;
 
        return bucket & (KEYRING_NAME_HASH_SIZE - 1);
 }
 
 /*
- * the keyring type definition
+ * 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_duplicate(struct key *keyring, const struct key *source);
 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,
@@ -58,25 +69,25 @@ struct key_type key_type_keyring = {
        .name           = "keyring",
        .def_datalen    = sizeof(struct keyring_list),
        .instantiate    = keyring_instantiate,
-       .duplicate      = keyring_duplicate,
        .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
+ * Semaphore to serialise link/link calls to prevent two link calls in parallel
+ * introducing a cycle.
  */
-DECLARE_RWSEM(keyring_serialise_link_sem);
+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)
+ * Publish the name of a keyring so that it can be found by name (if it has
+ * one).
  */
-void keyring_publish_name(struct key *keyring)
+static void keyring_publish_name(struct key *keyring)
 {
        int bucket;
 
@@ -93,13 +104,12 @@ void keyring_publish_name(struct key *keyring)
 
                write_unlock(&keyring_name_lock);
        }
+}
 
-} /* end keyring_publish_name() */
-
-/*****************************************************************************/
 /*
- * initialise a keyring
- * - we object if we were given any data
+ * 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)
@@ -114,85 +124,20 @@ static int keyring_instantiate(struct key *keyring,
        }
 
        return ret;
+}
 
-} /* end keyring_instantiate() */
-
-/*****************************************************************************/
-/*
- * duplicate the list of subscribed keys from a source keyring into this one
- */
-static int keyring_duplicate(struct key *keyring, const struct key *source)
-{
-       struct keyring_list *sklist, *klist;
-       unsigned max;
-       size_t size;
-       int loop, ret;
-
-       const unsigned limit =
-               (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key *);
-
-       ret = 0;
-
-       /* find out how many keys are currently linked */
-       rcu_read_lock();
-       sklist = rcu_dereference(source->payload.subscriptions);
-       max = 0;
-       if (sklist)
-               max = sklist->nkeys;
-       rcu_read_unlock();
-
-       /* allocate a new payload and stuff load with key links */
-       if (max > 0) {
-               BUG_ON(max > limit);
-
-               max = (max + 3) & ~3;
-               if (max > limit)
-                       max = limit;
-
-               ret = -ENOMEM;
-               size = sizeof(*klist) + sizeof(struct key *) * max;
-               klist = kmalloc(size, GFP_KERNEL);
-               if (!klist)
-                       goto error;
-
-               /* set links */
-               rcu_read_lock();
-               sklist = rcu_dereference(source->payload.subscriptions);
-
-               klist->maxkeys = max;
-               klist->nkeys = sklist->nkeys;
-               memcpy(klist->keys,
-                      sklist->keys,
-                      sklist->nkeys * sizeof(struct key *));
-
-               for (loop = klist->nkeys - 1; loop >= 0; loop--)
-                       atomic_inc(&klist->keys[loop]->usage);
-
-               rcu_read_unlock();
-
-               rcu_assign_pointer(keyring->payload.subscriptions, klist);
-               ret = 0;
-       }
-
- error:
-       return ret;
-
-} /* end keyring_duplicate() */
-
-/*****************************************************************************/
 /*
- * match keyrings on their name
+ * Match keyrings on their name
  */
 static int keyring_match(const struct key *keyring, const void *description)
 {
        return keyring->description &&
                strcmp(keyring->description, description) == 0;
+}
 
-} /* end keyring_match() */
-
-/*****************************************************************************/
 /*
- * dispose of the data dangling from the corpse of a keyring
+ * 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)
 {
@@ -209,44 +154,43 @@ static void keyring_destroy(struct key *keyring)
                write_unlock(&keyring_name_lock);
        }
 
-       klist = rcu_dereference(keyring->payload.subscriptions);
+       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);
        }
+}
 
-} /* end keyring_destroy() */
-
-/*****************************************************************************/
 /*
- * describe the keyring
+ * Describe a keyring for /proc.
  */
 static void keyring_describe(const struct key *keyring, struct seq_file *m)
 {
        struct keyring_list *klist;
 
-       if (keyring->description) {
+       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();
+               seq_puts(m, "[anon]");
 
-} /* end keyring_describe() */
+       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
- * - the keyring's semaphore is read-locked
+ * 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)
@@ -257,8 +201,7 @@ static long keyring_read(const struct key *keyring,
        int loop, ret;
 
        ret = 0;
-       klist = rcu_dereference(keyring->payload.subscriptions);
-
+       klist = rcu_dereference_locked_keyring(keyring);
        if (klist) {
                /* calculate how much data we could return */
                qty = klist->nkeys * sizeof(key_serial_t);
@@ -293,23 +236,24 @@ static long keyring_read(const struct key *keyring,
                ret = qty;
        }
 
- error:
+error:
        return ret;
+}
 
-} /* end keyring_read() */
-
-/*****************************************************************************/
 /*
- * allocate a keyring and link into the destination keyring
+ * Allocate a keyring and link into the destination keyring.
  */
 struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
-                         int not_in_quota, struct key *dest)
+                         const struct cred *cred, unsigned long flags,
+                         struct key *dest)
 {
        struct key *keyring;
        int ret;
 
        keyring = key_alloc(&key_type_keyring, description,
-                           uid, gid, KEY_POS_ALL | KEY_USR_ALL, not_in_quota);
+                           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);
@@ -320,26 +264,50 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
        }
 
        return keyring;
+}
 
-} /* end keyring_alloc() */
-
-/*****************************************************************************/
-/*
- * search the supplied keyring tree for a key that matches the criterion
- * - perform a breadth-then-depth search up to the prescribed limit
- * - we only find keys on which we have search permission
- * - we use the supplied match function to see if the description (or other
- *   feature of interest) matches
- * - we rely on RCU to prevent the keyring lists from disappearing on us
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we only found negative matching keys
- * - we propagate the possession attribute from the keyring ref to the key ref
+/**
+ * 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,
-                            struct task_struct *context,
+                            const struct cred *cred,
                             struct key_type *type,
                             const void *description,
-                            key_match_func_t match)
+                            key_match_func_t match,
+                            bool no_state_check)
 {
        struct {
                struct keyring_list *keylist;
@@ -348,7 +316,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
 
        struct keyring_list *keylist;
        struct timespec now;
-       unsigned long possessed;
+       unsigned long possessed, kflags;
        struct key *keyring, *key;
        key_ref_t key_ref;
        long err;
@@ -359,9 +327,11 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
        key_check(keyring);
 
        /* top keyring must have search permission to begin the search */
-       key_ref = ERR_PTR(-EACCES);
-       if (!key_task_permission(keyring_ref, context, KEY_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)
@@ -373,6 +343,34 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
        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))
@@ -385,30 +383,36 @@ descend:
        /* 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 (test_bit(KEY_FLAG_REVOKED, &key->flags))
-                       continue;
+               if (!no_state_check) {
+                       if (kflags & (1 << KEY_FLAG_REVOKED))
+                               continue;
 
-               if (key->expiry && now.tv_sec >= key->expiry)
-                       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),
-                                        context, KEY_SEARCH))
+               if (key_task_permission(make_key_ref(key, possessed),
+                                       cred, KEY_SEARCH) < 0)
                        continue;
 
-               /* we set a different error code if we find a negative key */
-               if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
-                       err = -ENOKEY;
+               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;
                }
 
@@ -429,8 +433,8 @@ ascend:
                if (sp >= KEYRING_SEARCH_MAX_DEPTH)
                        continue;
 
-               if (!key_task_permission(make_key_ref(key, possessed),
-                                        context, KEY_SEARCH))
+               if (key_task_permission(make_key_ref(key, possessed),
+                                       cred, KEY_SEARCH) < 0)
                        continue;
 
                /* stack the current position */
@@ -466,17 +470,16 @@ error_2:
        rcu_read_unlock();
 error:
        return key_ref;
+}
 
-} /* end keyring_search_aux() */
-
-/*****************************************************************************/
-/*
- * search the supplied keyring tree for a key that matches the criterion
- * - perform a breadth-then-depth search up to the prescribed limit
- * - we only find keys on which we have search permission
- * - we readlock the keyrings as we search down the tree
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we only found negative matching keys
+/**
+ * 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,
@@ -485,17 +488,25 @@ key_ref_t keyring_search(key_ref_t keyring,
        if (!type->match)
                return ERR_PTR(-ENOKEY);
 
-       return keyring_search_aux(keyring, current,
-                                 type, description, type->match);
-
-} /* end keyring_search() */
-
+       return keyring_search_aux(keyring, current->cred,
+                                 type, description, type->match, false);
+}
 EXPORT_SYMBOL(keyring_search);
 
-/*****************************************************************************/
 /*
- * search the given keyring only (no recursion)
- * - keyring must be locked by caller
+ * 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,
@@ -521,7 +532,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
                            (!key->type->match ||
                             key->type->match(key, description)) &&
                            key_permission(make_key_ref(key, possessed),
-                                          perm) &&
+                                          perm) == 0 &&
                            !test_bit(KEY_FLAG_REVOKED, &key->flags)
                            )
                                goto found;
@@ -531,73 +542,30 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
        rcu_read_unlock();
        return ERR_PTR(-ENOKEY);
 
- found:
+found:
        atomic_inc(&key->usage);
        rcu_read_unlock();
        return make_key_ref(key, possessed);
+}
 
-} /* end __keyring_search_one() */
-
-/*****************************************************************************/
-/*
- * search for an instantiation authorisation key matching a target key
- * - the RCU read lock must be held by the caller
- * - a target_id of zero specifies any valid token
- */
-struct key *keyring_search_instkey(struct key *keyring,
-                                  key_serial_t target_id)
-{
-       struct request_key_auth *rka;
-       struct keyring_list *klist;
-       struct key *instkey;
-       int loop;
-
-       klist = rcu_dereference(keyring->payload.subscriptions);
-       if (klist) {
-               for (loop = 0; loop < klist->nkeys; loop++) {
-                       instkey = klist->keys[loop];
-
-                       if (instkey->type != &key_type_request_key_auth)
-                               continue;
-
-                       rka = instkey->payload.data;
-                       if (target_id && rka->target_key->serial != target_id)
-                               continue;
-
-                       /* the auth key is revoked during instantiation */
-                       if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags))
-                               goto found;
-
-                       instkey = ERR_PTR(-EKEYREVOKED);
-                       goto error;
-               }
-       }
-
-       instkey = ERR_PTR(-EACCES);
-       goto error;
-
-found:
-       atomic_inc(&instkey->usage);
-error:
-       return instkey;
-
-} /* end keyring_search_instkey() */
-
-/*****************************************************************************/
 /*
- * find a keyring with the specified name
- * - all named keyrings are searched
- * - only find keyrings with search permission for the process
- * - only find keyrings with a serial number greater than the one specified
+ * 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, key_serial_t bound)
+struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
 {
        struct key *keyring;
        int bucket;
 
-       keyring = ERR_PTR(-EINVAL);
        if (!name)
-               goto error;
+               return ERR_PTR(-EINVAL);
 
        bucket = keyring_hash(name);
 
@@ -610,42 +578,41 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
                                    &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 (!key_permission(make_key_ref(keyring, 0),
-                                           KEY_SEARCH))
+                       if (!skip_perm_check &&
+                           key_permission(make_key_ref(keyring, 0),
+                                          KEY_SEARCH) < 0)
                                continue;
 
-                       /* found a potential candidate, but we still need to
-                        * check the serial number */
-                       if (keyring->serial <= bound)
+                       /* 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;
-
-                       /* we've got a match */
-                       atomic_inc(&keyring->usage);
-                       read_unlock(&keyring_name_lock);
-                       goto error;
+                       goto out;
                }
        }
 
-       read_unlock(&keyring_name_lock);
        keyring = ERR_PTR(-ENOKEY);
-
- error:
+out:
+       read_unlock(&keyring_name_lock);
        return keyring;
+}
 
-} /* end find_keyring_by_name() */
-
-/*****************************************************************************/
 /*
- * 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
+ * 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)
 {
@@ -668,7 +635,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
        sp = 0;
 
        /* start processing a new keyring */
- descend:
+descend:
        if (test_bit(KEY_FLAG_REVOKED, &subtree->flags))
                goto not_this_keyring;
 
@@ -677,7 +644,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
                goto not_this_keyring;
        kix = 0;
 
- ascend:
+ascend:
        /* iterate through the remaining keys in this keyring */
        for (; kix < keylist->nkeys; kix++) {
                key = keylist->keys[kix];
@@ -703,7 +670,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
 
        /* the keyring we're looking at was disqualified or didn't contain a
         * matching key */
- not_this_keyring:
+not_this_keyring:
        if (sp > 0) {
                /* resume the checking of a keyring higher up in the tree */
                sp--;
@@ -714,176 +681,298 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
 
        ret = 0; /* no cycles detected */
 
- error:
+error:
        rcu_read_unlock();
        return ret;
 
- too_deep:
+too_deep:
        ret = -ELOOP;
        goto error;
 
- cycle_detected:
+cycle_detected:
        ret = -EDEADLK;
        goto error;
+}
 
-} /* end keyring_detect_cycle() */
-
-/*****************************************************************************/
 /*
- * dispose of a keyring list after the RCU grace period
+ * Dispose of a keyring list after the RCU grace period, freeing the unlinked
+ * key
  */
-static void keyring_link_rcu_disposal(struct rcu_head *rcu)
+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);
+}
 
-} /* end keyring_link_rcu_disposal() */
-
-/*****************************************************************************/
 /*
- * link a key into to a keyring
- * - must be called with the keyring's semaphore write-locked
+ * Preallocate memory so that a key can be linked into to a keyring.
  */
-int __key_link(struct key *keyring, struct key *key)
+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 ret;
+       int loop, ret;
 
-       ret = -EKEYREVOKED;
-       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
-               goto error;
+       kenter("%d,%s,%s,", key_serial(keyring), type->name, description);
 
-       ret = -ENOTDIR;
        if (keyring->type != &key_type_keyring)
-               goto error;
+               return -ENOTDIR;
 
-       /* serialise link/link calls to prevent parallel calls causing a
-        * cycle when applied to two keyring in opposite orders */
-       down_write(&keyring_serialise_link_sem);
+       down_write(&keyring->sem);
 
-       /* check that we aren't going to create a cycle adding one keyring to
-        * another */
-       if (key->type == &key_type_keyring) {
-               ret = keyring_detect_cycle(keyring, key);
-               if (ret < 0)
-                       goto error2;
+       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 error2;
-
-       klist = keyring->payload.subscriptions;
+               goto error_sem;
 
        if (klist && klist->nkeys < klist->maxkeys) {
-               /* there's sufficient slack space to add directly */
-               atomic_inc(&key->usage);
-
-               klist->keys[klist->nkeys] = key;
-               smp_wmb();
-               klist->nkeys++;
-               smp_wmb();
-
-               ret = 0;
-       }
-       else {
+               /* 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 > 65535)
-                       goto error3;
+               if (max > USHRT_MAX - 1)
+                       goto error_quota;
                size = sizeof(*klist) + sizeof(struct key *) * max;
                if (size > PAGE_SIZE)
-                       goto error3;
+                       goto error_quota;
 
                ret = -ENOMEM;
                nklist = kmalloc(size, GFP_KERNEL);
                if (!nklist)
-                       goto error3;
-               nklist->maxkeys = max;
-               nklist->nkeys = 0;
+                       goto error_quota;
 
+               nklist->maxkeys = max;
                if (klist) {
-                       nklist->nkeys = klist->nkeys;
-                       memcpy(nklist->keys,
-                              klist->keys,
+                       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 */
-               atomic_inc(&key->usage);
-               nklist->keys[nklist->nkeys++] = key;
-
-               rcu_assign_pointer(keyring->payload.subscriptions, nklist);
-
-               /* dispose of the old keyring list */
-               if (klist)
-                       call_rcu(&klist->rcu, keyring_link_rcu_disposal);
-
-               ret = 0;
+               nklist->keys[nklist->delkey] = NULL;
        }
 
- error2:
-       up_write(&keyring_serialise_link_sem);
- error:
-       return ret;
+       prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA;
+done:
+       *_prealloc = prealloc;
+       kleave(" = 0");
+       return 0;
 
- error3:
+error_quota:
        /* undo the quota changes */
        key_payload_reserve(keyring,
                            keyring->datalen - KEYQUOTA_LINK_BYTES);
-       goto error2;
+error_sem:
+       if (type == &key_type_keyring)
+               up_write(&keyring_serialise_link_sem);
+error_krsem:
+       up_write(&keyring->sem);
+       kleave(" = %d", ret);
+       return ret;
+}
 
-} /* end __key_link() */
+/*
+ * 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 to a keyring
+ * 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.
  */
-int key_link(struct key *keyring, struct key *key)
+void __key_link(struct key *keyring, struct key *key,
+               unsigned long *_prealloc)
 {
-       int ret;
+       struct keyring_list *klist, *nklist;
 
-       key_check(keyring);
-       key_check(key);
+       nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA);
+       *_prealloc = 0;
 
-       down_write(&keyring->sem);
-       ret = __key_link(keyring, key);
-       up_write(&keyring->sem);
+       kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
 
-       return ret;
+       klist = rcu_dereference_protected(keyring->payload.subscriptions,
+                                         rwsem_is_locked(&keyring->sem));
 
-} /* end key_link() */
+       atomic_inc(&key->usage);
 
-EXPORT_SYMBOL(key_link);
+       /* 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++;
+       }
+}
 
-/*****************************************************************************/
 /*
- * dispose of a keyring list after the RCU grace period, freeing the unlinked
- * key
+ * Finish linking a key into to a keyring.
+ *
+ * Must be called with __key_link_begin() having being called.
  */
-static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
+void __key_link_end(struct key *keyring, struct key_type *type,
+                   unsigned long prealloc)
+       __releases(&keyring->sem)
 {
-       struct keyring_list *klist =
-               container_of(rcu, struct keyring_list, rcu);
+       BUG_ON(type == NULL);
+       BUG_ON(type->name == NULL);
+       kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
 
-       key_put(klist->keys[klist->delkey]);
-       kfree(klist);
+       if (type == &key_type_keyring)
+               up_write(&keyring_serialise_link_sem);
 
-} /* end keyring_unlink_rcu_disposal() */
+       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);
+}
 
-/*****************************************************************************/
-/*
- * unlink the first link to a key from a keyring
+/**
+ * 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)
 {
@@ -899,7 +988,7 @@ int key_unlink(struct key *keyring, struct key *key)
 
        down_write(&keyring->sem);
 
-       klist = keyring->payload.subscriptions;
+       klist = rcu_dereference_locked_keyring(keyring);
        if (klist) {
                /* search the keyring for the key */
                for (loop = 0; loop < klist->nkeys; loop++)
@@ -951,15 +1040,12 @@ nomem:
        ret = -ENOMEM;
        up_write(&keyring->sem);
        goto error;
-
-} /* end key_unlink() */
-
+}
 EXPORT_SYMBOL(key_unlink);
 
-/*****************************************************************************/
 /*
- * dispose of a keyring list after the RCU grace period, releasing the keys it
- * links to
+ * 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)
 {
@@ -972,13 +1058,15 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
                key_put(klist->keys[loop]);
 
        kfree(klist);
+}
 
-} /* end keyring_clear_rcu_disposal() */
-
-/*****************************************************************************/
-/*
- * clear the specified process keyring
- * - implements keyctl(KEYCTL_CLEAR)
+/**
+ * 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)
 {
@@ -990,7 +1078,7 @@ int keyring_clear(struct key *keyring)
                /* detach the pointer block with the locks held */
                down_write(&keyring->sem);
 
-               klist = keyring->payload.subscriptions;
+               klist = rcu_dereference_locked_keyring(keyring);
                if (klist) {
                        /* adjust the quota */
                        key_payload_reserve(keyring,
@@ -1010,7 +1098,129 @@ int keyring_clear(struct key *keyring)
        }
 
        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;
 
-} /* end keyring_clear() */
+       klist = rcu_dereference_locked_keyring(keyring);
 
-EXPORT_SYMBOL(keyring_clear);
+       /* 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]");
+}