clps711xfb: convert to proc_fops
[safe/jmp/linux-2.6] / security / keys / keyring.c
index 90a551e..8ec0274 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 <keys/keyring-type.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -47,8 +49,8 @@ static inline unsigned keyring_hash(const char *desc)
  */
 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 +60,27 @@ 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
  */
-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)
  */
-void keyring_publish_name(struct key *keyring)
+static void keyring_publish_name(struct key *keyring)
 {
        int bucket;
 
@@ -119,68 +123,6 @@ static int keyring_instantiate(struct key *keyring,
 
 /*****************************************************************************/
 /*
- * 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
  */
 static int keyring_match(const struct key *keyring, const void *description)
@@ -201,7 +143,11 @@ static void keyring_destroy(struct key *keyring)
 
        if (keyring->description) {
                write_lock(&keyring_name_lock);
-               list_del(&keyring->type_data.link);
+
+               if (keyring->type_data.link.next != NULL &&
+                   !list_empty(&keyring->type_data.link))
+                       list_del(&keyring->type_data.link);
+
                write_unlock(&keyring_name_lock);
        }
 
@@ -299,13 +245,16 @@ static long keyring_read(const struct key *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_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);
@@ -329,12 +278,13 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
  * - 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
  */
-struct key *keyring_search_aux(struct key *keyring,
-                              struct task_struct *context,
-                              struct key_type *type,
-                              const void *description,
-                              key_match_func_t match)
+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;
@@ -343,29 +293,61 @@ struct key *keyring_search_aux(struct key *keyring,
 
        struct keyring_list *keylist;
        struct timespec now;
-       struct key *key;
+       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);
 
-       rcu_read_lock();
-
        /* top keyring must have search permission to begin the search */
-       key = ERR_PTR(-EACCES);
-       if (!key_task_permission(keyring, context, KEY_SEARCH))
+        err = key_task_permission(keyring_ref, cred, KEY_SEARCH);
+       if (err < 0) {
+               key_ref = ERR_PTR(err);
                goto error;
+       }
 
-       key = ERR_PTR(-ENOTDIR);
+       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:
+descend:
        if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                goto not_this_keyring;
 
@@ -376,13 +358,14 @@ struct key *keyring_search_aux(struct key *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 (test_bit(KEY_FLAG_REVOKED, &key->flags))
+               if (kflags & (1 << KEY_FLAG_REVOKED))
                        continue;
 
                if (key->expiry && now.tv_sec >= key->expiry)
@@ -393,11 +376,12 @@ struct key *keyring_search_aux(struct key *keyring,
                        continue;
 
                /* key must have search permissions */
-               if (!key_task_permission(key, 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)) {
+               /* we set a different error code if we pass a negative key */
+               if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
                        err = -ENOKEY;
                        continue;
                }
@@ -407,7 +391,7 @@ struct key *keyring_search_aux(struct key *keyring,
 
        /* search through the keyrings nested in this one */
        kix = 0;
- ascend:
+ascend:
        for (; kix < keylist->nkeys; kix++) {
                key = keylist->keys[kix];
                if (key->type != &key_type_keyring)
@@ -419,7 +403,8 @@ struct key *keyring_search_aux(struct key *keyring,
                if (sp >= KEYRING_SEARCH_MAX_DEPTH)
                        continue;
 
-               if (!key_task_permission(key, context, KEY_SEARCH))
+               if (key_task_permission(make_key_ref(key, possessed),
+                                       cred, KEY_SEARCH) < 0)
                        continue;
 
                /* stack the current position */
@@ -434,7 +419,7 @@ struct key *keyring_search_aux(struct key *keyring,
 
        /* 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 processing of a keyring higher up in the tree */
                sp--;
@@ -443,16 +428,18 @@ struct key *keyring_search_aux(struct key *keyring,
                goto ascend;
        }
 
-       key = ERR_PTR(err);
-       goto error;
+       key_ref = ERR_PTR(err);
+       goto error_2;
 
        /* we found a viable match */
- found:
+found:
        atomic_inc(&key->usage);
        key_check(key);
- error:
+       key_ref = make_key_ref(key, possessed);
+error_2:
        rcu_read_unlock();
-       return key;
+error:
+       return key_ref;
 
 } /* end keyring_search_aux() */
 
@@ -465,14 +452,14 @@ struct key *keyring_search_aux(struct key *keyring,
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
-struct key *keyring_search(struct key *keyring,
-                          struct key_type *type,
-                          const char *description)
+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,
+       return keyring_search_aux(keyring, current->cred,
                                  type, description, type->match);
 
 } /* end keyring_search() */
@@ -483,16 +470,21 @@ EXPORT_SYMBOL(keyring_search);
 /*
  * search the given keyring only (no recursion)
  * - keyring must be locked by caller
+ * - caller must guarantee that the keyring is a keyring
  */
-struct key *__keyring_search_one(struct key *keyring,
-                                const struct key_type *ktype,
-                                const char *description,
-                                key_perm_t perm)
+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;
-       struct key *key;
+       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);
@@ -503,77 +495,31 @@ struct key *__keyring_search_one(struct key *keyring,
                        if (key->type == ktype &&
                            (!key->type->match ||
                             key->type->match(key, description)) &&
-                           key_permission(key, perm) &&
+                           key_permission(make_key_ref(key, possessed),
+                                          perm) == 0 &&
                            !test_bit(KEY_FLAG_REVOKED, &key->flags)
                            )
                                goto found;
                }
        }
 
-       key = ERR_PTR(-ENOKEY);
-       goto error;
+       rcu_read_unlock();
+       return ERR_PTR(-ENOKEY);
 
  found:
        atomic_inc(&key->usage);
- error:
        rcu_read_unlock();
-       return key;
+       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
+ * - normally only finds keyrings with search permission for the current process
  */
-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;
@@ -593,18 +539,18 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
                                    &keyring_name_hash[bucket],
                                    type_data.link
                                    ) {
-                       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
+                       if (keyring->user->user_ns != current_user_ns())
                                continue;
 
-                       if (strcmp(keyring->description, name) != 0)
+                       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                                continue;
 
-                       if (!key_permission(keyring, KEY_SEARCH))
+                       if (strcmp(keyring->description, name) != 0)
                                continue;
 
-                       /* found a potential candidate, but we still need to
-                        * check the serial number */
-                       if (keyring->serial <= bound)
+                       if (!skip_perm_check &&
+                           key_permission(make_key_ref(keyring, 0),
+                                          KEY_SEARCH) < 0)
                                continue;
 
                        /* we've got a match */
@@ -725,15 +671,31 @@ static void keyring_link_rcu_disposal(struct rcu_head *rcu)
 
 /*****************************************************************************/
 /*
+ * 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);
+
+       key_put(klist->keys[klist->delkey]);
+       kfree(klist);
+
+} /* end keyring_unlink_rcu_disposal() */
+
+/*****************************************************************************/
+/*
  * link a key into to a keyring
  * - must be called with the keyring's semaphore write-locked
+ * - discard already extant link to matching key if there is one
  */
 int __key_link(struct key *keyring, struct key *key)
 {
        struct keyring_list *klist, *nklist;
        unsigned max;
        size_t size;
-       int ret;
+       int loop, ret;
 
        ret = -EKEYREVOKED;
        if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
@@ -755,6 +717,46 @@ int __key_link(struct key *keyring, struct key *key)
                        goto error2;
        }
 
+       /* see if there's a matching key we can displace */
+       klist = keyring->payload.subscriptions;
+
+       if (klist && klist->nkeys > 0) {
+               struct key_type *type = key->type;
+
+               for (loop = klist->nkeys - 1; loop >= 0; loop--) {
+                       if (klist->keys[loop]->type == type &&
+                           strcmp(klist->keys[loop]->description,
+                                  key->description) == 0
+                           ) {
+                               /* found a match - replace with 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 error2;
+
+                               /* replace matched key */
+                               atomic_inc(&key->usage);
+                               nklist->keys[loop] = key;
+
+                               rcu_assign_pointer(
+                                       keyring->payload.subscriptions,
+                                       nklist);
+
+                               /* dispose of the old keyring list and the
+                                * displaced key */
+                               klist->delkey = loop;
+                               call_rcu(&klist->rcu,
+                                        keyring_unlink_rcu_disposal);
+
+                               goto done;
+                       }
+               }
+       }
+
        /* check that we aren't going to overrun the user's quota */
        ret = key_payload_reserve(keyring,
                                  keyring->datalen + KEYQUOTA_LINK_BYTES);
@@ -771,8 +773,6 @@ int __key_link(struct key *keyring, struct key *key)
                smp_wmb();
                klist->nkeys++;
                smp_wmb();
-
-               ret = 0;
        }
        else {
                /* grow the key list */
@@ -783,7 +783,7 @@ int __key_link(struct key *keyring, struct key *key)
                ret = -ENFILE;
                if (max > 65535)
                        goto error3;
-               size = sizeof(*klist) + sizeof(*key) * max;
+               size = sizeof(*klist) + sizeof(struct key *) * max;
                if (size > PAGE_SIZE)
                        goto error3;
 
@@ -810,16 +810,16 @@ int __key_link(struct key *keyring, struct key *key)
                /* dispose of the old keyring list */
                if (klist)
                        call_rcu(&klist->rcu, keyring_link_rcu_disposal);
-
-               ret = 0;
        }
 
- error2:
+done:
+       ret = 0;
+error2:
        up_write(&keyring_serialise_link_sem);
- error:
+error:
        return ret;
 
- error3:
+error3:
        /* undo the quota changes */
        key_payload_reserve(keyring,
                            keyring->datalen - KEYQUOTA_LINK_BYTES);
@@ -850,21 +850,6 @@ EXPORT_SYMBOL(key_link);
 
 /*****************************************************************************/
 /*
- * 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);
-
-       key_put(klist->keys[klist->delkey]);
-       kfree(klist);
-
-} /* end keyring_unlink_rcu_disposal() */
-
-/*****************************************************************************/
-/*
  * unlink the first link to a key from a keyring
  */
 int key_unlink(struct key *keyring, struct key *key)
@@ -895,7 +880,8 @@ int key_unlink(struct key *keyring, struct key *key)
 
 key_is_present:
        /* we need to copy the key list for RCU purposes */
-       nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys,
+       nklist = kmalloc(sizeof(*klist) +
+                        sizeof(struct key *) * klist->maxkeys,
                         GFP_KERNEL);
        if (!nklist)
                goto nomem;
@@ -905,12 +891,12 @@ key_is_present:
        if (loop > 0)
                memcpy(&nklist->keys[0],
                       &klist->keys[0],
-                      loop * sizeof(klist->keys[0]));
+                      loop * sizeof(struct key *));
 
        if (loop < nklist->nkeys)
                memcpy(&nklist->keys[loop],
                       &klist->keys[loop + 1],
-                      (nklist->nkeys - loop) * sizeof(klist->keys[0]));
+                      (nklist->nkeys - loop) * sizeof(struct key *));
 
        /* adjust the user's quota */
        key_payload_reserve(keyring,
@@ -995,3 +981,121 @@ int keyring_clear(struct key *keyring)
 } /* end keyring_clear() */
 
 EXPORT_SYMBOL(keyring_clear);
+
+/*****************************************************************************/
+/*
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+static void keyring_revoke(struct key *keyring)
+{
+       struct keyring_list *klist = keyring->payload.subscriptions;
+
+       /* 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);
+       }
+
+} /* end keyring_revoke() */
+
+/*
+ * 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
+ */
+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 = keyring->payload.subscriptions;
+       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]");
+}