]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - security/keys/keyring.c
UBUNTU: Start new release
[mirror_ubuntu-artful-kernel.git] / security / keys / keyring.c
index de81793f9920787101dec77eca28ddfbe91ebbc7..c04032302a2506e6ca65fd225c507cc3e56b6b35 100644 (file)
@@ -414,7 +414,7 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
        else
                seq_puts(m, "[anon]");
 
-       if (key_is_instantiated(keyring)) {
+       if (key_is_positive(keyring)) {
                if (keyring->keys.nr_leaves_on_tree != 0)
                        seq_printf(m, ": %lu", keyring->keys.nr_leaves_on_tree);
                else
@@ -423,7 +423,7 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
 }
 
 struct keyring_read_iterator_context {
-       size_t                  qty;
+       size_t                  buflen;
        size_t                  count;
        key_serial_t __user     *buffer;
 };
@@ -435,9 +435,9 @@ static int keyring_read_iterator(const void *object, void *data)
        int ret;
 
        kenter("{%s,%d},,{%zu/%zu}",
-              key->type->name, key->serial, ctx->count, ctx->qty);
+              key->type->name, key->serial, ctx->count, ctx->buflen);
 
-       if (ctx->count >= ctx->qty)
+       if (ctx->count >= ctx->buflen)
                return 1;
 
        ret = put_user(key->serial, ctx->buffer);
@@ -459,38 +459,33 @@ static long keyring_read(const struct key *keyring,
                         char __user *buffer, size_t buflen)
 {
        struct keyring_read_iterator_context ctx;
-       unsigned long nr_keys;
-       int ret;
+       long ret;
 
        kenter("{%d},,%zu", key_serial(keyring), buflen);
 
        if (buflen & (sizeof(key_serial_t) - 1))
                return -EINVAL;
 
-       nr_keys = keyring->keys.nr_leaves_on_tree;
-       if (nr_keys == 0)
-               return 0;
-
-       /* Calculate how much data we could return */
-       ctx.qty = nr_keys * sizeof(key_serial_t);
-
-       if (!buffer || !buflen)
-               return ctx.qty;
-
-       if (buflen > ctx.qty)
-               ctx.qty = buflen;
-
-       /* Copy the IDs of the subscribed keys into the buffer */
-       ctx.buffer = (key_serial_t __user *)buffer;
-       ctx.count = 0;
-       ret = assoc_array_iterate(&keyring->keys, keyring_read_iterator, &ctx);
-       if (ret < 0) {
-               kleave(" = %d [iterate]", ret);
-               return ret;
+       /* Copy as many key IDs as fit into the buffer */
+       if (buffer && buflen) {
+               ctx.buffer = (key_serial_t __user *)buffer;
+               ctx.buflen = buflen;
+               ctx.count = 0;
+               ret = assoc_array_iterate(&keyring->keys,
+                                         keyring_read_iterator, &ctx);
+               if (ret < 0) {
+                       kleave(" = %ld [iterate]", ret);
+                       return ret;
+               }
        }
 
-       kleave(" = %zu [ok]", ctx.count);
-       return ctx.count;
+       /* Return the size of the buffer needed */
+       ret = keyring->keys.nr_leaves_on_tree * sizeof(key_serial_t);
+       if (ret <= buflen)
+               kleave("= %ld [ok]", ret);
+       else
+               kleave("= %ld [buffer too small]", ret);
+       return ret;
 }
 
 /*
@@ -557,7 +552,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
 {
        struct keyring_search_context *ctx = iterator_data;
        const struct key *key = keyring_ptr_to_key(object);
-       unsigned long kflags = key->flags;
+       unsigned long kflags = READ_ONCE(key->flags);
+       short state = READ_ONCE(key->state);
 
        kenter("{%d}", key->serial);
 
@@ -601,9 +597,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
 
        if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
                /* we set a different error code if we pass a negative key */
-               if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
-                       smp_rmb();
-                       ctx->result = ERR_PTR(key->reject_error);
+               if (state < 0) {
+                       ctx->result = ERR_PTR(state);
                        kleave(" = %d [neg]", ctx->skipped_ret);
                        goto skipped;
                }
@@ -1101,15 +1096,15 @@ found:
 /*
  * 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.
+ * Only keyrings that have nonzero refcount, are not revoked, and are owned by a
+ * user in the current user namespace are considered.  If @uid_keyring is %true,
+ * the keyring additionally must have been allocated as a user or user session
+ * keyring; otherwise, it must grant Search permission directly to the caller.
  *
  * Returns a pointer to the keyring with the keyring's refcount having being
  * incremented on success.  -ENOKEY is returned if a key could not be found.
  */
-struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
+struct key *find_keyring_by_name(const char *name, bool uid_keyring)
 {
        struct key *keyring;
        int bucket;
@@ -1137,10 +1132,15 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
                        if (strcmp(keyring->description, name) != 0)
                                continue;
 
-                       if (!skip_perm_check &&
-                           key_permission(make_key_ref(keyring, 0),
-                                          KEY_NEED_SEARCH) < 0)
-                               continue;
+                       if (uid_keyring) {
+                               if (!test_bit(KEY_FLAG_UID_KEYRING,
+                                             &keyring->flags))
+                                       continue;
+                       } else {
+                               if (key_permission(make_key_ref(keyring, 0),
+                                                  KEY_NEED_SEARCH) < 0)
+                                       continue;
+                       }
 
                        /* we've got a match but we might end up racing with
                         * key_cleanup() if the keyring is currently 'dead'