]> Git Repo - J-linux.git/commitdiff
Merge tag 'keys-namespace-20190627' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <[email protected]>
Tue, 9 Jul 2019 02:36:47 +0000 (19:36 -0700)
committerLinus Torvalds <[email protected]>
Tue, 9 Jul 2019 02:36:47 +0000 (19:36 -0700)
Pull keyring namespacing from David Howells:
 "These patches help make keys and keyrings more namespace aware.

  Firstly some miscellaneous patches to make the process easier:

   - Simplify key index_key handling so that the word-sized chunks
     assoc_array requires don't have to be shifted about, making it
     easier to add more bits into the key.

   - Cache the hash value in the key so that we don't have to calculate
     on every key we examine during a search (it involves a bunch of
     multiplications).

   - Allow keying_search() to search non-recursively.

  Then the main patches:

   - Make it so that keyring names are per-user_namespace from the point
     of view of KEYCTL_JOIN_SESSION_KEYRING so that they're not
     accessible cross-user_namespace.

     keyctl_capabilities() shows KEYCTL_CAPS1_NS_KEYRING_NAME for this.

   - Move the user and user-session keyrings to the user_namespace
     rather than the user_struct. This prevents them propagating
     directly across user_namespaces boundaries (ie. the KEY_SPEC_*
     flags will only pick from the current user_namespace).

   - Make it possible to include the target namespace in which the key
     shall operate in the index_key. This will allow the possibility of
     multiple keys with the same description, but different target
     domains to be held in the same keyring.

     keyctl_capabilities() shows KEYCTL_CAPS1_NS_KEY_TAG for this.

   - Make it so that keys are implicitly invalidated by removal of a
     domain tag, causing them to be garbage collected.

   - Institute a network namespace domain tag that allows keys to be
     differentiated by the network namespace in which they operate. New
     keys that are of a type marked 'KEY_TYPE_NET_DOMAIN' are assigned
     the network domain in force when they are created.

   - Make it so that the desired network namespace can be handed down
     into the request_key() mechanism. This allows AFS, NFS, etc. to
     request keys specific to the network namespace of the superblock.

     This also means that the keys in the DNS record cache are
     thenceforth namespaced, provided network filesystems pass the
     appropriate network namespace down into dns_query().

     For DNS, AFS and NFS are good, whilst CIFS and Ceph are not. Other
     cache keyrings, such as idmapper keyrings, also need to set the
     domain tag - for which they need access to the network namespace of
     the superblock"

* tag 'keys-namespace-20190627' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  keys: Pass the network namespace into request_key mechanism
  keys: Network namespace domain tag
  keys: Garbage collect keys for which the domain has been removed
  keys: Include target namespace in match criteria
  keys: Move the user and user-session keyrings to the user_namespace
  keys: Namespace keyring names
  keys: Add a 'recurse' flag for keyring searches
  keys: Cache the hash value to avoid lots of recalculation
  keys: Simplify key description management

23 files changed:
1  2 
certs/blacklist.c
crypto/asymmetric_keys/asymmetric_type.c
fs/afs/addr_list.c
fs/afs/dynroot.c
include/linux/key-type.h
include/linux/key.h
kernel/user.c
kernel/user_namespace.c
lib/digsig.c
net/core/net_namespace.c
net/rxrpc/key.c
net/rxrpc/security.c
security/integrity/digsig_asymmetric.c
security/keys/gc.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/persistent.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c

diff --combined certs/blacklist.c
index f1a8672123c3981358da437c062a22c33348ca98,181cb7fa95400625363eb5cfd9e6347832b81998..ec00bf337eb673b28bced4f1521d9d0a007a0c2e
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* System hash blacklist.
   *
   * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  
  #define pr_fmt(fmt) "blacklist: "fmt
@@@ -124,7 -128,7 +124,7 @@@ int is_hash_blacklisted(const u8 *hash
        *p = 0;
  
        kref = keyring_search(make_key_ref(blacklist_keyring, true),
-                             &key_type_blacklist, buffer);
+                             &key_type_blacklist, buffer, false);
        if (!IS_ERR(kref)) {
                key_ref_put(kref);
                ret = -EKEYREJECTED;
index 01945ab46382b74e35ff6d9b3a7b423267dae95d,084027ef31214c6314e58fe5bbbededf269838c3..6e5fc8e31f01d5d274c5f4d3bcd1e1a9207beb54
@@@ -1,10 -1,14 +1,10 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Asymmetric public-key cryptography key type
   *
   * See Documentation/crypto/asymmetric-keys.txt
   *
   * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  #include <keys/asymmetric-subtype.h>
  #include <keys/asymmetric-parser.h>
@@@ -83,7 -87,7 +83,7 @@@ struct key *find_asymmetric_key(struct 
        pr_debug("Look up: \"%s\"\n", req);
  
        ref = keyring_search(make_key_ref(keyring, 1),
-                            &key_type_asymmetric, req);
+                            &key_type_asymmetric, req, true);
        if (IS_ERR(ref))
                pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
        kfree(req);
diff --combined fs/afs/addr_list.c
index 86da532c192f9381d7b4477c563a46b70d7165d8,6b1e8fc6c9540a3cdbc37ef43c997a93dc7a8946..df415c05939e7ad4f5d7716d68e4f2bead7eecf7
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Server address list management
   *
   * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  
  #include <linux/slab.h>
@@@ -246,8 -250,8 +246,8 @@@ struct afs_vlserver_list *afs_dns_query
  
        _enter("%s", cell->name);
  
-       ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
-                       &result, _expiry, true);
+       ret = dns_query(cell->net->net, "afsdb", cell->name, cell->name_len,
+                       "srv=1", &result, _expiry, true);
        if (ret < 0) {
                _leave(" = %d [dns]", ret);
                return ERR_PTR(ret);
diff --combined fs/afs/dynroot.c
index 9b3b2f1f1fc0d00b52f565b8a19e269a31359121,b075605b0c450759bcf2c10fe2ab8f1e99b4661d..bcd1bafb027845a7931a600dfff13328242c51fb
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* AFS dynamic root handling
   *
   * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  
  #include <linux/fs.h>
@@@ -24,6 -28,7 +24,7 @@@ const struct file_operations afs_dynroo
  static int afs_probe_cell_name(struct dentry *dentry)
  {
        struct afs_cell *cell;
+       struct afs_net *net = afs_d2net(dentry);
        const char *name = dentry->d_name.name;
        size_t len = dentry->d_name.len;
        int ret;
                len--;
        }
  
-       cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
+       cell = afs_lookup_cell_rcu(net, name, len);
        if (!IS_ERR(cell)) {
-               afs_put_cell(afs_d2net(dentry), cell);
+               afs_put_cell(net, cell);
                return 0;
        }
  
-       ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL, false);
+       ret = dns_query(net->net, "afsdb", name, len, "srv=1",
+                       NULL, NULL, false);
        if (ret == -ENODATA)
                ret = -EDESTADDRREQ;
        return ret;
diff --combined include/linux/key-type.h
index 331cab70db0974c289bd1c2400342329ee39184f,2148a6bf58f1e2d78a802ca7ab1faa49aa96c7ae..4ded94bcf2748a995e901e1893a1ed5fd67e5179
@@@ -1,8 -1,12 +1,8 @@@
 +/* SPDX-License-Identifier: GPL-2.0-or-later */
  /* Definitions for key type implementations
   *
   * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  
  #ifndef _LINUX_KEY_TYPE_H
@@@ -70,6 -74,9 +70,9 @@@ struct key_type 
         */
        size_t def_datalen;
  
+       unsigned int flags;
+ #define KEY_TYPE_NET_DOMAIN   0x00000001 /* Keys of this type have a net namespace domain */
        /* vet a description */
        int (*vet_description)(const char *description);
  
diff --combined include/linux/key.h
index ad17c8f30b4c32f0e05df1986c11209a224b49be,18d7f62ab6b02c6771264f857b0087f79d19731e..91f391cd272e094d3d74683f08ac226fe8e1ce20
@@@ -1,9 -1,14 +1,9 @@@
 +/* SPDX-License-Identifier: GPL-2.0-or-later */
  /* Authentication token and access key management
   *
   * Copyright (C) 2004, 2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
   *
 - * 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.
 - *
 - *
   * See Documentation/security/keys/core.rst for information on keys/keyrings.
   */
  
@@@ -31,6 -36,7 +31,7 @@@ typedef int32_t key_serial_t
  typedef uint32_t key_perm_t;
  
  struct key;
+ struct net;
  
  #ifdef CONFIG_KEYS
  
@@@ -77,13 -83,34 +78,34 @@@ struct cred
  
  struct key_type;
  struct key_owner;
+ struct key_tag;
  struct keyring_list;
  struct keyring_name;
  
+ struct key_tag {
+       struct rcu_head         rcu;
+       refcount_t              usage;
+       bool                    removed;        /* T when subject removed */
+ };
  struct keyring_index_key {
+       /* [!] If this structure is altered, the union in struct key must change too! */
+       unsigned long           hash;                   /* Hash value */
+       union {
+               struct {
+ #ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */
+                       u8      desc_len;
+                       char    desc[sizeof(long) - 1]; /* First few chars of description */
+ #else
+                       char    desc[sizeof(long) - 1]; /* First few chars of description */
+                       u8      desc_len;
+ #endif
+               };
+               unsigned long x;
+       };
        struct key_type         *type;
+       struct key_tag          *domain_tag;    /* Domain of operation */
        const char              *description;
-       size_t                  desc_len;
  };
  
  union key_payload {
@@@ -197,7 -224,10 +219,10 @@@ struct key 
        union {
                struct keyring_index_key index_key;
                struct {
+                       unsigned long   hash;
+                       unsigned long   len_desc;
                        struct key_type *type;          /* type of key */
+                       struct key_tag  *domain_tag;    /* Domain of operation */
                        char            *description;
                };
        };
@@@ -248,6 -278,8 +273,8 @@@ extern struct key *key_alloc(struct key
  extern void key_revoke(struct key *key);
  extern void key_invalidate(struct key *key);
  extern void key_put(struct key *key);
+ extern bool key_put_tag(struct key_tag *tag);
+ extern void key_remove_domain(struct key_tag *domain_tag);
  
  static inline struct key *__key_get(struct key *key)
  {
@@@ -265,19 -297,57 +292,57 @@@ static inline void key_ref_put(key_ref_
        key_put(key_ref_to_ptr(key_ref));
  }
  
- extern struct key *request_key(struct key_type *type,
-                              const char *description,
-                              const char *callout_info);
+ extern struct key *request_key_tag(struct key_type *type,
+                                  const char *description,
+                                  struct key_tag *domain_tag,
+                                  const char *callout_info);
  
  extern struct key *request_key_rcu(struct key_type *type,
-                                  const char *description);
+                                  const char *description,
+                                  struct key_tag *domain_tag);
  
  extern struct key *request_key_with_auxdata(struct key_type *type,
                                            const char *description,
+                                           struct key_tag *domain_tag,
                                            const void *callout_info,
                                            size_t callout_len,
                                            void *aux);
  
+ /**
+  * request_key - Request a key and wait for construction
+  * @type: Type of key.
+  * @description: The searchable description of the key.
+  * @callout_info: The data to pass to the instantiation upcall (or NULL).
+  *
+  * As for request_key_tag(), but with the default global domain tag.
+  */
+ static inline struct key *request_key(struct key_type *type,
+                                     const char *description,
+                                     const char *callout_info)
+ {
+       return request_key_tag(type, description, NULL, callout_info);
+ }
+ #ifdef CONFIG_NET
+ /*
+  * request_key_net - Request a key for a net namespace and wait for construction
+  * @type: Type of key.
+  * @description: The searchable description of the key.
+  * @net: The network namespace that is the key's domain of operation.
+  * @callout_info: The data to pass to the instantiation upcall (or NULL).
+  *
+  * As for request_key() except that it does not add the returned key to a
+  * keyring if found, new keys are always allocated in the user's quota, the
+  * callout_info must be a NUL-terminated string and no auxiliary data can be
+  * passed.  Only keys that operate the specified network namespace are used.
+  *
+  * Furthermore, it then works as wait_for_key_construction() to wait for the
+  * completion of keys undergoing construction with a non-interruptible wait.
+  */
+ #define request_key_net(type, description, net, callout_info) \
+       request_key_tag(type, description, net->key_domain, callout_info);
+ #endif /* CONFIG_NET */
  extern int wait_for_key_construction(struct key *key, bool intr);
  
  extern int key_validate(const struct key *key);
@@@ -321,7 -391,8 +386,8 @@@ extern int keyring_clear(struct key *ke
  
  extern key_ref_t keyring_search(key_ref_t keyring,
                                struct key_type *type,
-                               const char *description);
+                               const char *description,
+                               bool recurse);
  
  extern int keyring_add_key(struct key *keyring,
                           struct key *key);
@@@ -340,6 -411,7 +406,7 @@@ extern void key_set_timeout(struct key 
  
  extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
                                 key_perm_t perm);
+ extern void key_free_user_ns(struct user_namespace *);
  
  /*
   * The permissions required on a key that we're looking up.
@@@ -413,6 -485,8 +480,8 @@@ extern void key_init(void)
  #define key_fsuid_changed(c)          do { } while(0)
  #define key_fsgid_changed(c)          do { } while(0)
  #define key_init()                    do { } while(0)
+ #define key_free_user_ns(ns)          do { } while(0)
+ #define key_remove_domain(d)          do { } while(0)
  
  #endif /* CONFIG_KEYS */
  #endif /* __KERNEL__ */
diff --combined kernel/user.c
index 78b17e36e705c2b81f76637b327c7f5a79e194ad,f8519b62cf9a2fd1f07c865cc8659e114d4b13b8..5235d7f49982e5e228256fe01b96164c41aa7b82
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * The "user cache".
   *
@@@ -63,9 -62,9 +63,9 @@@ struct user_namespace init_user_ns = 
        .ns.ops = &userns_operations,
  #endif
        .flags = USERNS_INIT_FLAGS,
- #ifdef CONFIG_PERSISTENT_KEYRINGS
-       .persistent_keyring_register_sem =
-       __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
+ #ifdef CONFIG_KEYS
+       .keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
+       .keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem),
  #endif
  };
  EXPORT_SYMBOL_GPL(init_user_ns);
@@@ -141,8 -140,6 +141,6 @@@ static void free_user(struct user_struc
  {
        uid_hash_remove(up);
        spin_unlock_irqrestore(&uidhash_lock, flags);
-       key_put(up->uid_keyring);
-       key_put(up->session_keyring);
        kmem_cache_free(uid_cachep, up);
  }
  
diff --combined kernel/user_namespace.c
index 0eff45ce7703f2a7d37c291fe6c3ae18aba81797,c87c2ecc70854db8f9a14907bddfa5a917ad2326..8eadadc478f9aa2c76693d9809b23726152650c2
@@@ -1,4 -1,9 +1,4 @@@
 -/*
 - *  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, version 2 of the
 - *  License.
 - */
 +// SPDX-License-Identifier: GPL-2.0-only
  
  #include <linux/export.h>
  #include <linux/nsproxy.h>
@@@ -128,8 -133,9 +128,9 @@@ int create_user_ns(struct cred *new
        ns->flags = parent_ns->flags;
        mutex_unlock(&userns_state_mutex);
  
- #ifdef CONFIG_PERSISTENT_KEYRINGS
-       init_rwsem(&ns->persistent_keyring_register_sem);
+ #ifdef CONFIG_KEYS
+       INIT_LIST_HEAD(&ns->keyring_name_list);
+       init_rwsem(&ns->keyring_sem);
  #endif
        ret = -ENOMEM;
        if (!setup_userns_sysctls(ns))
@@@ -191,9 -197,7 +192,7 @@@ static void free_user_ns(struct work_st
                        kfree(ns->projid_map.reverse);
                }
                retire_userns_sysctls(ns);
- #ifdef CONFIG_PERSISTENT_KEYRINGS
-               key_put(ns->persistent_keyring_register);
- #endif
+               key_free_user_ns(ns);
                ns_free_inum(&ns->ns);
                kmem_cache_free(user_ns_cachep, ns);
                dec_user_namespaces(ucounts);
diff --combined lib/digsig.c
index 3cf89c775ab2f9e7ba974bcbb57509832f3d0341,3782af401c685c92f5f224beb61cf24fcf957ee7..e0627c3e53b2e77ea3d0835e1b7666e24da5e93d
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * Copyright (C) 2011 Nokia Corporation
   * Copyright (C) 2011 Intel Corporation
@@@ -7,6 -6,10 +7,6 @@@
   * Dmitry Kasatkin <[email protected]>
   *                 <[email protected]>
   *
 - * 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, version 2 of the License.
 - *
   * File: sign.c
   *    implements signature (RSA) verification
   *    pkcs decoding is based on LibTomCrypt code
@@@ -218,7 -221,7 +218,7 @@@ int digsig_verify(struct key *keyring, 
                /* search in specific keyring */
                key_ref_t kref;
                kref = keyring_search(make_key_ref(keyring, 1UL),
-                                               &key_type_user, name);
+                                     &key_type_user, name, true);
                if (IS_ERR(kref))
                        key = ERR_CAST(kref);
                else
diff --combined net/core/net_namespace.c
index 15f68842ac6b4c32845d9550f2b2e89ca4406999,88e603b85ed256ef1dddb22ea2b4b852e048004f..f7b6dda798e00b0b6e695f3c3949799a59449d28
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/workqueue.h>
@@@ -39,9 -38,16 +39,16 @@@ EXPORT_SYMBOL_GPL(net_namespace_list)
  DECLARE_RWSEM(net_rwsem);
  EXPORT_SYMBOL_GPL(net_rwsem);
  
+ #ifdef CONFIG_KEYS
+ static struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) };
+ #endif
  struct net init_net = {
        .count          = REFCOUNT_INIT(1),
        .dev_base_head  = LIST_HEAD_INIT(init_net.dev_base_head),
+ #ifdef CONFIG_KEYS
+       .key_domain     = &init_net_key_domain,
+ #endif
  };
  EXPORT_SYMBOL(init_net);
  
@@@ -387,10 -393,22 +394,22 @@@ static struct net *net_alloc(void
        if (!net)
                goto out_free;
  
+ #ifdef CONFIG_KEYS
+       net->key_domain = kzalloc(sizeof(struct key_tag), GFP_KERNEL);
+       if (!net->key_domain)
+               goto out_free_2;
+       refcount_set(&net->key_domain->usage, 1);
+ #endif
        rcu_assign_pointer(net->gen, ng);
  out:
        return net;
  
+ #ifdef CONFIG_KEYS
+ out_free_2:
+       kmem_cache_free(net_cachep, net);
+       net = NULL;
+ #endif
  out_free:
        kfree(ng);
        goto out;
@@@ -567,6 -585,7 +586,7 @@@ static void cleanup_net(struct work_str
        list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
                list_del_init(&net->exit_list);
                dec_net_namespaces(net->ucounts);
+               key_remove_domain(net->key_domain);
                put_user_ns(net->user_ns);
                net_drop_ns(net);
        }
diff --combined net/rxrpc/key.c
index 83e3357a65a6966f4e16f9f791f3c97bfe334656,1cc6b0c6cc429559b8d02c0ca5814c60f75e23af..6c3f35fac42d57eeb4449e403c4267ae7bcb9d11
@@@ -1,9 -1,13 +1,9 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* RxRPC key management
   *
   * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
   *
 - * 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.
 - *
   * RxRPC keys should have a description of describing their purpose:
   *    "[email protected]>
   */
@@@ -39,6 -43,7 +39,7 @@@ static long rxrpc_read(const struct ke
   */
  struct key_type key_type_rxrpc = {
        .name           = "rxrpc",
+       .flags          = KEY_TYPE_NET_DOMAIN,
        .preparse       = rxrpc_preparse,
        .free_preparse  = rxrpc_free_preparse,
        .instantiate    = generic_key_instantiate,
@@@ -54,6 -59,7 +55,7 @@@ EXPORT_SYMBOL(key_type_rxrpc)
   */
  struct key_type key_type_rxrpc_s = {
        .name           = "rxrpc_s",
+       .flags          = KEY_TYPE_NET_DOMAIN,
        .vet_description = rxrpc_vet_description_s,
        .preparse       = rxrpc_preparse_s,
        .free_preparse  = rxrpc_free_preparse_s,
@@@ -908,7 -914,7 +910,7 @@@ int rxrpc_request_key(struct rxrpc_soc
        if (IS_ERR(description))
                return PTR_ERR(description);
  
-       key = request_key(&key_type_rxrpc, description, NULL);
+       key = request_key_net(&key_type_rxrpc, description, sock_net(&rx->sk), NULL);
        if (IS_ERR(key)) {
                kfree(description);
                _leave(" = %ld", PTR_ERR(key));
@@@ -939,7 -945,7 +941,7 @@@ int rxrpc_server_keyring(struct rxrpc_s
        if (IS_ERR(description))
                return PTR_ERR(description);
  
-       key = request_key(&key_type_keyring, description, NULL);
+       key = request_key_net(&key_type_keyring, description, sock_net(&rx->sk), NULL);
        if (IS_ERR(key)) {
                kfree(description);
                _leave(" = %ld", PTR_ERR(key));
diff --combined net/rxrpc/security.c
index 2e78f0cc7ef1c956b13f821426f6febb22056bae,2cfc7125bc41edb4baf26cc66e8ac834f81bbeeb..a4c47d2b705478eabf87b699da6852207f525f56
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* RxRPC security handling
   *
   * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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>
@@@ -144,7 -148,7 +144,7 @@@ found_service
  
        /* look through the service's keyring */
        kref = keyring_search(make_key_ref(rx->securities, 1UL),
-                             &key_type_rxrpc_s, kdesc);
+                             &key_type_rxrpc_s, kdesc, true);
        if (IS_ERR(kref)) {
                read_unlock(&local->services_lock);
                _leave(" = %ld [search]", PTR_ERR(kref));
index ad4b323ecea119a5aeb118d430e9a3d281ac0577,358f614811e8440279d0cca92024b3b112b069b1..55aec161d0e1c9e73cda8fab91ca5442065162d2
@@@ -1,9 -1,13 +1,9 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * Copyright (C) 2013 Intel Corporation
   *
   * Author:
   * Dmitry Kasatkin <[email protected]>
 - *
 - * 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, version 2 of the License.
 - *
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@@ -35,7 -39,7 +35,7 @@@ static struct key *request_asymmetric_k
                key_ref_t kref;
  
                kref = keyring_search(make_key_ref(key, 1),
-                                    &key_type_asymmetric, name);
+                                     &key_type_asymmetric, name, true);
                if (!IS_ERR(kref)) {
                        pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
                        return ERR_PTR(-EKEYREJECTED);
@@@ -47,7 -51,7 +47,7 @@@
                key_ref_t kref;
  
                kref = keyring_search(make_key_ref(keyring, 1),
-                                     &key_type_asymmetric, name);
+                                     &key_type_asymmetric, name, true);
                if (IS_ERR(kref))
                        key = ERR_CAST(kref);
                else
diff --combined security/keys/gc.c
index 44e58a3e5663642719178d1628cb81064df8b180,83d279fb7793712a17b971ec49d85ddfc0810699..671dd730ecfc9e62395b2a7bf046f76f0f9ad313
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Key garbage collector
   *
   * Copyright (C) 2009-2011 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  
  #include <linux/slab.h>
@@@ -150,7 -154,7 +150,7 @@@ static noinline void key_gc_unused_keys
                        atomic_dec(&key->user->nikeys);
  
                key_user_put(key->user);
+               key_put_tag(key->domain_tag);
                kfree(key->description);
  
                memzero_explicit(key, sizeof(*key));
diff --combined security/keys/internal.h
index 663f291e30d4ad9f896cbb28ed1c0a2f6e8cef16,f1f2b076f3a1c703ffe1a4aa4f90f4fc64797837..c039373488bd940d2a1c6dac919e46e586cd3002
@@@ -1,8 -1,12 +1,8 @@@
 +/* SPDX-License-Identifier: GPL-2.0-or-later */
  /* Authentication token and access key management internal defs
   *
   * Copyright (C) 2003-5, 2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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.
   */
  
  #ifndef _INTERNAL_H
@@@ -85,7 -89,7 +85,7 @@@ extern spinlock_t key_serial_lock
  extern struct mutex key_construction_mutex;
  extern wait_queue_head_t request_key_conswq;
  
+ extern void key_set_index_key(struct keyring_index_key *index_key);
  extern struct key_type *key_type_lookup(const char *type);
  extern void key_type_put(struct key_type *ktype);
  
@@@ -123,6 -127,7 +123,7 @@@ struct keyring_search_context 
  #define KEYRING_SEARCH_NO_CHECK_PERM  0x0008  /* Don't check permissions */
  #define KEYRING_SEARCH_DETECT_TOO_DEEP        0x0010  /* Give an error on excessive depth */
  #define KEYRING_SEARCH_SKIP_EXPIRED   0x0020  /* Ignore expired keys (intention to replace) */
+ #define KEYRING_SEARCH_RECURSE                0x0040  /* Search child keyrings also */
  
        int (*iterator)(const void *object, void *iterator_data);
  
@@@ -143,13 -148,15 +144,15 @@@ extern key_ref_t search_process_keyring
  
  extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
  
- extern int install_user_keyrings(void);
+ extern int look_up_user_keyrings(struct key **, struct key **);
+ extern struct key *get_user_session_keyring_rcu(const struct cred *);
  extern int install_thread_keyring_to_cred(struct cred *);
  extern int install_process_keyring_to_cred(struct cred *);
  extern int install_session_keyring_to_cred(struct cred *, struct key *);
  
  extern struct key *request_key_and_link(struct key_type *type,
                                        const char *description,
+                                       struct key_tag *domain_tag,
                                        const void *callout_info,
                                        size_t callout_len,
                                        void *aux,
@@@ -203,7 -210,8 +206,8 @@@ static inline bool key_is_dead(const st
        return
                key->flags & ((1 << KEY_FLAG_DEAD) |
                              (1 << KEY_FLAG_INVALIDATED)) ||
-               (key->expiry > 0 && key->expiry <= limit);
+               (key->expiry > 0 && key->expiry <= limit) ||
+               key->domain_tag->removed;
  }
  
  /*
diff --combined security/keys/key.c
index 85dddc0190a7bdb7ea2d2001f19342c50291beb9,85fdc2ea6c146454ef3083e9536aaa223bd10b73..764f4c57913e95ee5836e523079f7bdb30f6a695
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Basic authentication token and access key management
   *
   * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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/export.h>
@@@ -281,11 -285,12 +281,12 @@@ struct key *key_alloc(struct key_type *
        key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
        if (!key->index_key.description)
                goto no_memory_3;
+       key->index_key.type = type;
+       key_set_index_key(&key->index_key);
  
        refcount_set(&key->usage, 1);
        init_rwsem(&key->sem);
        lockdep_set_class(&key->sem, &type->lock_class);
-       key->index_key.type = type;
        key->user = user;
        key->quotalen = quotalen;
        key->datalen = type->def_datalen;
                goto security_error;
  
        /* publish the key by giving it a serial number */
+       refcount_inc(&key->domain_tag->usage);
        atomic_inc(&user->nkeys);
        key_alloc_serial(key);
  
@@@ -864,6 -870,7 +866,7 @@@ key_ref_t key_create_or_update(key_ref_
                        goto error_free_prep;
        }
        index_key.desc_len = strlen(index_key.description);
+       key_set_index_key(&index_key);
  
        ret = __key_link_lock(keyring, &index_key);
        if (ret < 0) {
diff --combined security/keys/keyctl.c
index 741e4ba382df5c38fca63884daa2739ab1f85fb2,d2f8eabcbcf4f5fa1864f34237826fe60f5e0a8d..9b898c9695583da389c4129544081c334f679e26
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Userspace key control operations
   *
   * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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/init.h>
@@@ -26,7 -30,7 +26,7 @@@
  
  #define KEY_MAX_DESC_SIZE 4096
  
- static const unsigned char keyrings_capabilities[1] = {
+ static const unsigned char keyrings_capabilities[2] = {
        [0] = (KEYCTL_CAPS0_CAPABILITIES |
               (IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS)  ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) |
               (IS_ENABLED(CONFIG_KEY_DH_OPERATIONS)    ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) |
@@@ -36,6 -40,8 +36,8 @@@
               KEYCTL_CAPS0_RESTRICT_KEYRING |
               KEYCTL_CAPS0_MOVE
               ),
+       [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME |
+              KEYCTL_CAPS1_NS_KEY_TAG),
  };
  
  static int key_get_type_from_user(char *type,
@@@ -218,7 -224,7 +220,7 @@@ SYSCALL_DEFINE4(request_key, const cha
        }
  
        /* do the search */
-       key = request_key_and_link(ktype, description, callout_info,
+       key = request_key_and_link(ktype, description, NULL, callout_info,
                                   callout_len, NULL, key_ref_to_ptr(dest_ref),
                                   KEY_ALLOC_IN_QUOTA);
        if (IS_ERR(key)) {
@@@ -758,7 -764,7 +760,7 @@@ long keyctl_keyring_search(key_serial_
        }
  
        /* do the search */
-       key_ref = keyring_search(keyring_ref, ktype, description);
+       key_ref = keyring_search(keyring_ref, ktype, description, true);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
  
diff --combined security/keys/keyring.c
index e4de4070c75467eba765e93740a24f60c43f0374,29c31585ed61acf02c3d649cf54ad44d312f5f48..febf36c6ddc5dbc06098dd5913f77fba115f78bf
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Keyring handling
   *
   * Copyright (C) 2004-2005, 2008, 2013 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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/export.h>
  #include <linux/security.h>
  #include <linux/seq_file.h>
  #include <linux/err.h>
+ #include <linux/user_namespace.h>
+ #include <linux/nsproxy.h>
  #include <keys/keyring-type.h>
  #include <keys/user-type.h>
  #include <linux/assoc_array_priv.h>
  #include <linux/uaccess.h>
+ #include <net/net_namespace.h>
  #include "internal.h"
  
  /*
   */
  #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)
  /*
   * We mark pointers we pass to the associative array with bit 1 set if
   * they're keyrings and clear otherwise.
@@@ -51,17 -53,21 +49,21 @@@ static inline void *keyring_key_to_ptr(
        return key;
  }
  
- 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)
+ /*
+  * Clean up the bits of user_namespace that belong to us.
+  */
+ void key_free_user_ns(struct user_namespace *ns)
  {
-       unsigned bucket = 0;
-       for (; *desc; desc++)
-               bucket += (unsigned char)*desc;
-       return bucket & (KEYRING_NAME_HASH_SIZE - 1);
+       write_lock(&keyring_name_lock);
+       list_del_init(&ns->keyring_name_list);
+       write_unlock(&keyring_name_lock);
+       key_put(ns->user_keyring_register);
+ #ifdef CONFIG_PERSISTENT_KEYRINGS
+       key_put(ns->persistent_keyring_register);
+ #endif
  }
  
  /*
@@@ -100,23 -106,17 +102,17 @@@ static DEFINE_MUTEX(keyring_serialise_l
  
  /*
   * Publish the name of a keyring so that it can be found by name (if it has
-  * one).
+  * one and it doesn't begin with a dot).
   */
  static void keyring_publish_name(struct key *keyring)
  {
-       int bucket;
-       if (keyring->description) {
-               bucket = keyring_hash(keyring->description);
+       struct user_namespace *ns = current_user_ns();
  
+       if (keyring->description &&
+           keyring->description[0] &&
+           keyring->description[0] != '.') {
                write_lock(&keyring_name_lock);
-               if (!keyring_name_hash[bucket].next)
-                       INIT_LIST_HEAD(&keyring_name_hash[bucket]);
-               list_add_tail(&keyring->name_link,
-                             &keyring_name_hash[bucket]);
+               list_add_tail(&keyring->name_link, &ns->keyring_name_list);
                write_unlock(&keyring_name_lock);
        }
  }
@@@ -164,7 -164,7 +160,7 @@@ static u64 mult_64x32_and_fold(u64 x, u
  /*
   * Hash a key type and description.
   */
- static unsigned long hash_key_type_and_desc(const struct keyring_index_key *index_key)
+ static void hash_key_type_and_desc(struct keyring_index_key *index_key)
  {
        const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP;
        const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK;
        int n, desc_len = index_key->desc_len;
  
        type = (unsigned long)index_key->type;
        acc = mult_64x32_and_fold(type, desc_len + 13);
        acc = mult_64x32_and_fold(acc, 9207);
+       piece = (unsigned long)index_key->domain_tag;
+       acc = mult_64x32_and_fold(acc, piece);
+       acc = mult_64x32_and_fold(acc, 9207);
        for (;;) {
                n = desc_len;
                if (n <= 0)
         * zero for keyrings and non-zero otherwise.
         */
        if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0)
-               return hash | (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1;
-       if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0)
-               return (hash + (hash << level_shift)) & ~fan_mask;
-       return hash;
+               hash |= (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1;
+       else if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0)
+               hash = (hash + (hash << level_shift)) & ~fan_mask;
+       index_key->hash = hash;
  }
  
  /*
-  * Build the next index key chunk.
-  *
-  * On 32-bit systems the index key is laid out as:
-  *
-  *    0       4       5       9...
-  *    hash    desclen typeptr desc[]
+  * Finalise an index key to include a part of the description actually in the
+  * index key, to set the domain tag and to calculate the hash.
+  */
+ void key_set_index_key(struct keyring_index_key *index_key)
+ {
+       static struct key_tag default_domain_tag = { .usage = REFCOUNT_INIT(1), };
+       size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
+       memcpy(index_key->desc, index_key->description, n);
+       if (!index_key->domain_tag) {
+               if (index_key->type->flags & KEY_TYPE_NET_DOMAIN)
+                       index_key->domain_tag = current->nsproxy->net_ns->key_domain;
+               else
+                       index_key->domain_tag = &default_domain_tag;
+       }
+       hash_key_type_and_desc(index_key);
+ }
+ /**
+  * key_put_tag - Release a ref on a tag.
+  * @tag: The tag to release.
   *
-  * On 64-bit systems:
+  * This releases a reference the given tag and returns true if that ref was the
+  * last one.
+  */
+ bool key_put_tag(struct key_tag *tag)
+ {
+       if (refcount_dec_and_test(&tag->usage)) {
+               kfree_rcu(tag, rcu);
+               return true;
+       }
+       return false;
+ }
+ /**
+  * key_remove_domain - Kill off a key domain and gc its keys
+  * @domain_tag: The domain tag to release.
   *
-  *    0       8       9       17...
-  *    hash    desclen typeptr desc[]
+  * This marks a domain tag as being dead and releases a ref on it.  If that
+  * wasn't the last reference, the garbage collector is poked to try and delete
+  * all keys that were in the domain.
+  */
+ void key_remove_domain(struct key_tag *domain_tag)
+ {
+       domain_tag->removed = true;
+       if (!key_put_tag(domain_tag))
+               key_schedule_gc_links();
+ }
+ /*
+  * Build the next index key chunk.
   *
   * We return it one word-sized chunk at a time.
   */
@@@ -227,41 -273,33 +269,33 @@@ static unsigned long keyring_get_key_ch
  {
        const struct keyring_index_key *index_key = data;
        unsigned long chunk = 0;
-       long offset = 0;
+       const u8 *d;
        int desc_len = index_key->desc_len, n = sizeof(chunk);
  
        level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
        switch (level) {
        case 0:
-               return hash_key_type_and_desc(index_key);
+               return index_key->hash;
        case 1:
-               return ((unsigned long)index_key->type << 8) | desc_len;
+               return index_key->x;
        case 2:
-               if (desc_len == 0)
-                       return (u8)((unsigned long)index_key->type >>
-                                   (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8));
-               n--;
-               offset = 1;
-               /* fall through */
+               return (unsigned long)index_key->type;
+       case 3:
+               return (unsigned long)index_key->domain_tag;
        default:
-               offset += sizeof(chunk) - 1;
-               offset += (level - 3) * sizeof(chunk);
-               if (offset >= desc_len)
+               level -= 4;
+               if (desc_len <= sizeof(index_key->desc))
                        return 0;
-               desc_len -= offset;
+               d = index_key->description + sizeof(index_key->desc);
+               d += level * sizeof(long);
+               desc_len -= sizeof(index_key->desc);
                if (desc_len > n)
                        desc_len = n;
-               offset += desc_len;
                do {
                        chunk <<= 8;
-                       chunk |= ((u8*)index_key->description)[--offset];
+                       chunk |= *d++;
                } while (--desc_len > 0);
-               if (level == 2) {
-                       chunk <<= 8;
-                       chunk |= (u8)((unsigned long)index_key->type >>
-                                     (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8));
-               }
                return chunk;
        }
  }
@@@ -278,6 -316,7 +312,7 @@@ static bool keyring_compare_object(cons
        const struct key *key = keyring_ptr_to_key(object);
  
        return key->index_key.type == index_key->type &&
+               key->index_key.domain_tag == index_key->domain_tag &&
                key->index_key.desc_len == index_key->desc_len &&
                memcmp(key->index_key.description, index_key->description,
                       index_key->desc_len) == 0;
@@@ -296,43 -335,38 +331,38 @@@ static int keyring_diff_objects(const v
        int level, i;
  
        level = 0;
-       seg_a = hash_key_type_and_desc(a);
-       seg_b = hash_key_type_and_desc(b);
+       seg_a = a->hash;
+       seg_b = b->hash;
        if ((seg_a ^ seg_b) != 0)
                goto differ;
+       level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;
  
        /* The number of bits contributed by the hash is controlled by a
         * constant in the assoc_array headers.  Everything else thereafter we
         * can deal with as being machine word-size dependent.
         */
-       level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;
-       seg_a = a->desc_len;
-       seg_b = b->desc_len;
+       seg_a = a->x;
+       seg_b = b->x;
        if ((seg_a ^ seg_b) != 0)
                goto differ;
+       level += sizeof(unsigned long);
  
        /* The next bit may not work on big endian */
-       level++;
        seg_a = (unsigned long)a->type;
        seg_b = (unsigned long)b->type;
        if ((seg_a ^ seg_b) != 0)
                goto differ;
+       level += sizeof(unsigned long);
  
+       seg_a = (unsigned long)a->domain_tag;
+       seg_b = (unsigned long)b->domain_tag;
+       if ((seg_a ^ seg_b) != 0)
+               goto differ;
        level += sizeof(unsigned long);
-       if (a->desc_len == 0)
-               goto same;
  
-       i = 0;
-       if (((unsigned long)a->description | (unsigned long)b->description) &
-           (sizeof(unsigned long) - 1)) {
-               do {
-                       seg_a = *(unsigned long *)(a->description + i);
-                       seg_b = *(unsigned long *)(b->description + i);
-                       if ((seg_a ^ seg_b) != 0)
-                               goto differ_plus_i;
-                       i += sizeof(unsigned long);
-               } while (i < (a->desc_len & (sizeof(unsigned long) - 1)));
-       }
+       i = sizeof(a->desc);
+       if (a->desc_len <= i)
+               goto same;
  
        for (; i < a->desc_len; i++) {
                seg_a = *(unsigned char *)(a->description + i);
@@@ -658,6 -692,9 +688,9 @@@ static bool search_nested_keyrings(stru
        BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
               (ctx->flags & STATE_CHECKS) == STATE_CHECKS);
  
+       if (ctx->index_key.description)
+               key_set_index_key(&ctx->index_key);
        /* Check to see if this top-level keyring is what we are looking for
         * and whether it is valid or not.
         */
@@@ -697,6 -734,9 +730,9 @@@ descend_to_keyring
         * Non-keyrings avoid the leftmost branch of the root entirely (root
         * slots 1-15).
         */
+       if (!(ctx->flags & KEYRING_SEARCH_RECURSE))
+               goto not_this_keyring;
        ptr = READ_ONCE(keyring->keys.root);
        if (!ptr)
                goto not_this_keyring;
@@@ -897,13 -937,15 +933,15 @@@ key_ref_t keyring_search_rcu(key_ref_t 
   * @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.
+  * @recurse: True to search the children of @keyring also
   *
   * As keyring_search_rcu() above, but using the current task's credentials and
   * type's default matching function and preferred search method.
   */
  key_ref_t keyring_search(key_ref_t keyring,
                         struct key_type *type,
-                        const char *description)
+                        const char *description,
+                        bool recurse)
  {
        struct keyring_search_context ctx = {
                .index_key.type         = type,
        key_ref_t key;
        int ret;
  
+       if (recurse)
+               ctx.flags |= KEYRING_SEARCH_RECURSE;
        if (type->match_preparse) {
                ret = type->match_preparse(&ctx.match_data);
                if (ret < 0)
@@@ -1102,50 -1146,44 +1142,44 @@@ found
   */
  struct key *find_keyring_by_name(const char *name, bool uid_keyring)
  {
+       struct user_namespace *ns = current_user_ns();
        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],
-                                   name_link
-                                   ) {
-                       if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
-                               continue;
-                       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
-                               continue;
+       /* Search this hash bucket for a keyring with a matching name that
+        * grants Search permission and that hasn't been revoked
+        */
+       list_for_each_entry(keyring, &ns->keyring_name_list, name_link) {
+               if (!kuid_has_mapping(ns, keyring->user->uid))
+                       continue;
  
-                       if (strcmp(keyring->description, name) != 0)
-                               continue;
+               if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
+                       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;
-                       }
+               if (strcmp(keyring->description, name) != 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 (!refcount_inc_not_zero(&keyring->usage))
+               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;
-                       keyring->last_used_at = ktime_get_real_seconds();
-                       goto out;
                }
+               /* 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 (!refcount_inc_not_zero(&keyring->usage))
+                       continue;
+               keyring->last_used_at = ktime_get_real_seconds();
+               goto out;
        }
  
        keyring = ERR_PTR(-ENOKEY);
@@@ -1188,7 -1226,8 +1222,8 @@@ static int keyring_detect_cycle(struct 
                .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
                                           KEYRING_SEARCH_NO_UPDATE_TIME |
                                           KEYRING_SEARCH_NO_CHECK_PERM |
-                                          KEYRING_SEARCH_DETECT_TOO_DEEP),
+                                          KEYRING_SEARCH_DETECT_TOO_DEEP |
+                                          KEYRING_SEARCH_RECURSE),
        };
  
        rcu_read_lock();
index da9a0f42b79500e0e76da06a13d2a5c32c4ccbf3,9944d855a28d520c956b995572db802d7b6fe0f8..97af230aa4b22b3667e7098558bdff933a7b5bb4
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* General persistent per-UID keyrings register
   *
   * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * This program is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU General Public Licence
 - * as published by the Free Software Foundation; either version
 - * 2 of the Licence, or (at your option) any later version.
   */
  
  #include <linux/user_namespace.h>
@@@ -80,15 -84,17 +80,17 @@@ static long key_get_persistent(struct u
        long ret;
  
        /* Look in the register if it exists */
+       memset(&index_key, 0, sizeof(index_key));
        index_key.type = &key_type_keyring;
        index_key.description = buf;
        index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid));
+       key_set_index_key(&index_key);
  
        if (ns->persistent_keyring_register) {
                reg_ref = make_key_ref(ns->persistent_keyring_register, true);
-               down_read(&ns->persistent_keyring_register_sem);
+               down_read(&ns->keyring_sem);
                persistent_ref = find_key_to_update(reg_ref, &index_key);
-               up_read(&ns->persistent_keyring_register_sem);
+               up_read(&ns->keyring_sem);
  
                if (persistent_ref)
                        goto found;
        /* It wasn't in the register, so we'll need to create it.  We might
         * also need to create the register.
         */
-       down_write(&ns->persistent_keyring_register_sem);
+       down_write(&ns->keyring_sem);
        persistent_ref = key_create_persistent(ns, uid, &index_key);
-       up_write(&ns->persistent_keyring_register_sem);
+       up_write(&ns->keyring_sem);
        if (!IS_ERR(persistent_ref))
                goto found;
  
diff --combined security/keys/proc.c
index 7f15550c10f5f8cacc29fdd13fec7b6a4724cfbc,b4f5ba56b9cb996b655ef569c335cc2215944062..415f3f1c2da042f794608522aeddd772fc706011
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* procfs files for key database enumeration
   *
   * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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/init.h>
@@@ -166,7 -170,8 +166,8 @@@ static int proc_keys_show(struct seq_fi
                .match_data.cmp         = lookup_user_key_possessed,
                .match_data.raw_data    = key,
                .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
-               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
+               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
+                                          KEYRING_SEARCH_RECURSE),
        };
  
        key_ref = make_key_ref(key, 0);
index b99ad2c5342f28f857a09fdff67ad1937884e1b4,f74d6421594229a71511a316f1d18ae5c6cb5159..09541de31f2f14def6209b939cd1f3e9b3447c18
@@@ -1,8 -1,12 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Manage a process's keyrings
   *
   * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
 - *
 - * 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/init.h>
  #include <linux/security.h>
  #include <linux/user_namespace.h>
  #include <linux/uaccess.h>
+ #include <linux/init_task.h>
  #include <keys/request_key_auth-type.h>
  #include "internal.h"
  
  /* Session keyring create vs join semaphore */
  static DEFINE_MUTEX(key_session_mutex);
  
- /* User keyring creation semaphore */
- static DEFINE_MUTEX(key_user_keyring_mutex);
  /* The root user's tracking struct */
  struct key_user root_key_user = {
        .usage          = REFCOUNT_INIT(3),
  };
  
  /*
-  * Install the user and user session keyrings for the current process's UID.
+  * Get or create a user register keyring.
+  */
+ static struct key *get_user_register(struct user_namespace *user_ns)
+ {
+       struct key *reg_keyring = READ_ONCE(user_ns->user_keyring_register);
+       if (reg_keyring)
+               return reg_keyring;
+       down_write(&user_ns->keyring_sem);
+       /* Make sure there's a register keyring.  It gets owned by the
+        * user_namespace's owner.
+        */
+       reg_keyring = user_ns->user_keyring_register;
+       if (!reg_keyring) {
+               reg_keyring = keyring_alloc(".user_reg",
+                                           user_ns->owner, INVALID_GID,
+                                           &init_cred,
+                                           KEY_POS_WRITE | KEY_POS_SEARCH |
+                                           KEY_USR_VIEW | KEY_USR_READ,
+                                           0,
+                                           NULL, NULL);
+               if (!IS_ERR(reg_keyring))
+                       smp_store_release(&user_ns->user_keyring_register,
+                                         reg_keyring);
+       }
+       up_write(&user_ns->keyring_sem);
+       /* We don't return a ref since the keyring is pinned by the user_ns */
+       return reg_keyring;
+ }
+ /*
+  * Look up the user and user session keyrings for the current process's UID,
+  * creating them if they don't exist.
   */
- int install_user_keyrings(void)
+ int look_up_user_keyrings(struct key **_user_keyring,
+                         struct key **_user_session_keyring)
  {
-       struct user_struct *user;
-       const struct cred *cred;
-       struct key *uid_keyring, *session_keyring;
+       const struct cred *cred = current_cred();
+       struct user_namespace *user_ns = current_user_ns();
+       struct key *reg_keyring, *uid_keyring, *session_keyring;
        key_perm_t user_keyring_perm;
+       key_ref_t uid_keyring_r, session_keyring_r;
+       uid_t uid = from_kuid(user_ns, cred->user->uid);
        char buf[20];
        int ret;
-       uid_t uid;
  
        user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL;
-       cred = current_cred();
-       user = cred->user;
-       uid = from_kuid(cred->user_ns, user->uid);
  
-       kenter("%p{%u}", user, uid);
+       kenter("%u", uid);
  
-       if (READ_ONCE(user->uid_keyring) && READ_ONCE(user->session_keyring)) {
-               kleave(" = 0 [exist]");
-               return 0;
-       }
+       reg_keyring = get_user_register(user_ns);
+       if (IS_ERR(reg_keyring))
+               return PTR_ERR(reg_keyring);
  
-       mutex_lock(&key_user_keyring_mutex);
+       down_write(&user_ns->keyring_sem);
        ret = 0;
  
-       if (!user->uid_keyring) {
-               /* get the UID-specific keyring
-                * - there may be one in existence already as it may have been
-                *   pinned by a session, but the user_struct pointing to it
-                *   may have been destroyed by setuid */
-               sprintf(buf, "_uid.%u", uid);
-               uid_keyring = find_keyring_by_name(buf, true);
+       /* Get the user keyring.  Note that there may be one in existence
+        * already as it may have been pinned by a session, but the user_struct
+        * pointing to it may have been destroyed by setuid.
+        */
+       snprintf(buf, sizeof(buf), "_uid.%u", uid);
+       uid_keyring_r = keyring_search(make_key_ref(reg_keyring, true),
+                                      &key_type_keyring, buf, false);
+       kdebug("_uid %p", uid_keyring_r);
+       if (uid_keyring_r == ERR_PTR(-EAGAIN)) {
+               uid_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID,
+                                           cred, user_keyring_perm,
+                                           KEY_ALLOC_UID_KEYRING |
+                                           KEY_ALLOC_IN_QUOTA,
+                                           NULL, reg_keyring);
                if (IS_ERR(uid_keyring)) {
-                       uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
-                                                   cred, user_keyring_perm,
-                                                   KEY_ALLOC_UID_KEYRING |
-                                                       KEY_ALLOC_IN_QUOTA,
-                                                   NULL, NULL);
-                       if (IS_ERR(uid_keyring)) {
-                               ret = PTR_ERR(uid_keyring);
-                               goto error;
-                       }
+                       ret = PTR_ERR(uid_keyring);
+                       goto error;
                }
+       } else if (IS_ERR(uid_keyring_r)) {
+               ret = PTR_ERR(uid_keyring_r);
+               goto error;
+       } else {
+               uid_keyring = key_ref_to_ptr(uid_keyring_r);
+       }
  
-               /* get a default session keyring (which might also exist
-                * already) */
-               sprintf(buf, "_uid_ses.%u", uid);
-               session_keyring = find_keyring_by_name(buf, true);
+       /* Get a default session keyring (which might also exist already) */
+       snprintf(buf, sizeof(buf), "_uid_ses.%u", uid);
+       session_keyring_r = keyring_search(make_key_ref(reg_keyring, true),
+                                          &key_type_keyring, buf, false);
+       kdebug("_uid_ses %p", session_keyring_r);
+       if (session_keyring_r == ERR_PTR(-EAGAIN)) {
+               session_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID,
+                                               cred, user_keyring_perm,
+                                               KEY_ALLOC_UID_KEYRING |
+                                               KEY_ALLOC_IN_QUOTA,
+                                               NULL, NULL);
                if (IS_ERR(session_keyring)) {
-                       session_keyring =
-                               keyring_alloc(buf, user->uid, INVALID_GID,
-                                             cred, user_keyring_perm,
-                                             KEY_ALLOC_UID_KEYRING |
-                                                 KEY_ALLOC_IN_QUOTA,
-                                             NULL, NULL);
-                       if (IS_ERR(session_keyring)) {
-                               ret = PTR_ERR(session_keyring);
-                               goto error_release;
-                       }
-                       /* we install a link from the user session keyring to
-                        * the user keyring */
-                       ret = key_link(session_keyring, uid_keyring);
-                       if (ret < 0)
-                               goto error_release_both;
+                       ret = PTR_ERR(session_keyring);
+                       goto error_release;
                }
  
-               /* install the keyrings */
-               /* paired with READ_ONCE() */
-               smp_store_release(&user->uid_keyring, uid_keyring);
-               /* paired with READ_ONCE() */
-               smp_store_release(&user->session_keyring, session_keyring);
+               /* We install a link from the user session keyring to
+                * the user keyring.
+                */
+               ret = key_link(session_keyring, uid_keyring);
+               if (ret < 0)
+                       goto error_release_session;
+               /* And only then link the user-session keyring to the
+                * register.
+                */
+               ret = key_link(reg_keyring, session_keyring);
+               if (ret < 0)
+                       goto error_release_session;
+       } else if (IS_ERR(session_keyring_r)) {
+               ret = PTR_ERR(session_keyring_r);
+               goto error_release;
+       } else {
+               session_keyring = key_ref_to_ptr(session_keyring_r);
        }
  
-       mutex_unlock(&key_user_keyring_mutex);
+       up_write(&user_ns->keyring_sem);
+       if (_user_session_keyring)
+               *_user_session_keyring = session_keyring;
+       else
+               key_put(session_keyring);
+       if (_user_keyring)
+               *_user_keyring = uid_keyring;
+       else
+               key_put(uid_keyring);
        kleave(" = 0");
        return 0;
  
- error_release_both:
+ error_release_session:
        key_put(session_keyring);
  error_release:
        key_put(uid_keyring);
  error:
-       mutex_unlock(&key_user_keyring_mutex);
+       up_write(&user_ns->keyring_sem);
        kleave(" = %d", ret);
        return ret;
  }
  
+ /*
+  * Get the user session keyring if it exists, but don't create it if it
+  * doesn't.
+  */
+ struct key *get_user_session_keyring_rcu(const struct cred *cred)
+ {
+       struct key *reg_keyring = READ_ONCE(cred->user_ns->user_keyring_register);
+       key_ref_t session_keyring_r;
+       char buf[20];
+       struct keyring_search_context ctx = {
+               .index_key.type         = &key_type_keyring,
+               .index_key.description  = buf,
+               .cred                   = cred,
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = buf,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_DO_STATE_CHECK,
+       };
+       if (!reg_keyring)
+               return NULL;
+       ctx.index_key.desc_len = snprintf(buf, sizeof(buf), "_uid_ses.%u",
+                                         from_kuid(cred->user_ns,
+                                                   cred->user->uid));
+       session_keyring_r = keyring_search_rcu(make_key_ref(reg_keyring, true),
+                                              &ctx);
+       if (IS_ERR(session_keyring_r))
+               return NULL;
+       return key_ref_to_ptr(session_keyring_r);
+ }
  /*
   * Install a thread keyring to the given credentials struct if it didn't have
   * one already.  This is allowed to overrun the quota.
@@@ -336,6 -425,7 +421,7 @@@ void key_fsgid_changed(struct cred *new
   */
  key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx)
  {
+       struct key *user_session;
        key_ref_t key_ref, ret, err;
        const struct cred *cred = ctx->cred;
  
                }
        }
        /* or search the user-session keyring */
-       else if (READ_ONCE(cred->user->session_keyring)) {
-               key_ref = keyring_search_rcu(
-                       make_key_ref(READ_ONCE(cred->user->session_keyring), 1),
-                       ctx);
+       else if ((user_session = get_user_session_keyring_rcu(cred))) {
+               key_ref = keyring_search_rcu(make_key_ref(user_session, 1),
+                                            ctx);
+               key_put(user_session);
                if (!IS_ERR(key_ref))
                        goto found;
  
@@@ -527,10 -618,11 +614,11 @@@ key_ref_t lookup_user_key(key_serial_t 
        struct keyring_search_context ctx = {
                .match_data.cmp         = lookup_user_key_possessed,
                .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
-               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
+               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
+                                          KEYRING_SEARCH_RECURSE),
        };
        struct request_key_auth *rka;
-       struct key *key;
+       struct key *key, *user_session;
        key_ref_t key_ref, skey_ref;
        int ret;
  
@@@ -579,20 -671,20 +667,20 @@@ try_again
                if (!ctx.cred->session_keyring) {
                        /* always install a session keyring upon access if one
                         * doesn't exist yet */
-                       ret = install_user_keyrings();
+                       ret = look_up_user_keyrings(NULL, &user_session);
                        if (ret < 0)
                                goto error;
                        if (lflags & KEY_LOOKUP_CREATE)
                                ret = join_session_keyring(NULL);
                        else
-                               ret = install_session_keyring(
-                                       ctx.cred->user->session_keyring);
+                               ret = install_session_keyring(user_session);
  
+                       key_put(user_session);
                        if (ret < 0)
                                goto error;
                        goto reget_creds;
-               } else if (ctx.cred->session_keyring ==
-                          READ_ONCE(ctx.cred->user->session_keyring) &&
+               } else if (test_bit(KEY_FLAG_UID_KEYRING,
+                                   &ctx.cred->session_keyring->flags) &&
                           lflags & KEY_LOOKUP_CREATE) {
                        ret = join_session_keyring(NULL);
                        if (ret < 0)
                break;
  
        case KEY_SPEC_USER_KEYRING:
-               if (!READ_ONCE(ctx.cred->user->uid_keyring)) {
-                       ret = install_user_keyrings();
-                       if (ret < 0)
-                               goto error;
-               }
-               key = ctx.cred->user->uid_keyring;
-               __key_get(key);
+               ret = look_up_user_keyrings(&key, NULL);
+               if (ret < 0)
+                       goto error;
                key_ref = make_key_ref(key, 1);
                break;
  
        case KEY_SPEC_USER_SESSION_KEYRING:
-               if (!READ_ONCE(ctx.cred->user->session_keyring)) {
-                       ret = install_user_keyrings();
-                       if (ret < 0)
-                               goto error;
-               }
-               key = ctx.cred->user->session_keyring;
-               __key_get(key);
+               ret = look_up_user_keyrings(NULL, &key);
+               if (ret < 0)
+                       goto error;
                key_ref = make_key_ref(key, 1);
                break;
  
@@@ -874,7 -956,7 +952,7 @@@ void key_change_session_keyring(struct 
   */
  static int __init init_root_keyring(void)
  {
-       return install_user_keyrings();
+       return look_up_user_keyrings(NULL, NULL);
  }
  
  late_initcall(init_root_keyring);
index f2b4da143963d37b58951e6d41ab50e2f3995310,aa589d3c90e2fa6d5a1d75c0636d525f3f7ec85b..7325f382dbf43b5660d0f3938e0ce18b737bed6e
@@@ -1,9 -1,13 +1,9 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Request a key from userspace
   *
   * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
   *
 - * 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.
 - *
   * See Documentation/security/keys/request-key.rst
   */
  
@@@ -13,6 -17,7 +13,7 @@@
  #include <linux/err.h>
  #include <linux/keyctl.h>
  #include <linux/slab.h>
+ #include <net/net_namespace.h>
  #include "internal.h"
  #include <keys/request_key_auth-type.h>
  
@@@ -117,7 -122,7 +118,7 @@@ static int call_sbin_request_key(struc
        struct request_key_auth *rka = get_request_key_auth(authkey);
        const struct cred *cred = current_cred();
        key_serial_t prkey, sskey;
-       struct key *key = rka->target_key, *keyring, *session;
+       struct key *key = rka->target_key, *keyring, *session, *user_session;
        char *argv[9], *envp[3], uid_str[12], gid_str[12];
        char key_str[12], keyring_str[3][12];
        char desc[20];
  
        kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op);
  
-       ret = install_user_keyrings();
+       ret = look_up_user_keyrings(NULL, &user_session);
        if (ret < 0)
-               goto error_alloc;
+               goto error_us;
  
        /* allocate a new session keyring */
        sprintf(desc, "_req.%u", key->serial);
  
        session = cred->session_keyring;
        if (!session)
-               session = cred->user->session_keyring;
+               session = user_session;
        sskey = session->serial;
  
        sprintf(keyring_str[2], "%d", sskey);
@@@ -207,6 -212,8 +208,8 @@@ error_link
        key_put(keyring);
  
  error_alloc:
+       key_put(user_session);
+ error_us:
        complete_request_key(authkey, ret);
        kleave(" = %d", ret);
        return ret;
@@@ -313,13 -320,15 +316,15 @@@ static int construct_get_dest_keyring(s
  
                        /* fall through */
                case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
-                       dest_keyring =
-                               key_get(READ_ONCE(cred->user->session_keyring));
+                       ret = look_up_user_keyrings(NULL, &dest_keyring);
+                       if (ret < 0)
+                               return ret;
                        break;
  
                case KEY_REQKEY_DEFL_USER_KEYRING:
-                       dest_keyring =
-                               key_get(READ_ONCE(cred->user->uid_keyring));
+                       ret = look_up_user_keyrings(&dest_keyring, NULL);
+                       if (ret < 0)
+                               return ret;
                        break;
  
                case KEY_REQKEY_DEFL_GROUP_KEYRING:
@@@ -525,16 -534,18 +530,18 @@@ error
   * request_key_and_link - Request a key and cache it in a keyring.
   * @type: The type of key we want.
   * @description: The searchable description of the key.
+  * @domain_tag: The domain in which the key operates.
   * @callout_info: The data to pass to the instantiation upcall (or NULL).
   * @callout_len: The length of callout_info.
   * @aux: Auxiliary data for the upcall.
   * @dest_keyring: Where to cache the key.
   * @flags: Flags to key_alloc().
   *
-  * A key matching the specified criteria is searched for in the process's
-  * keyrings and returned with its usage count incremented if found.  Otherwise,
-  * if callout_info is not NULL, a key will be allocated and some service
-  * (probably in userspace) will be asked to instantiate it.
+  * A key matching the specified criteria (type, description, domain_tag) is
+  * searched for in the process's keyrings and returned with its usage count
+  * incremented if found.  Otherwise, if callout_info is not NULL, a key will be
+  * allocated and some service (probably in userspace) will be asked to
+  * instantiate it.
   *
   * If successfully found or created, the key will be linked to the destination
   * keyring if one is provided.
   */
  struct key *request_key_and_link(struct key_type *type,
                                 const char *description,
+                                struct key_tag *domain_tag,
                                 const void *callout_info,
                                 size_t callout_len,
                                 void *aux,
  {
        struct keyring_search_context ctx = {
                .index_key.type         = type,
+               .index_key.domain_tag   = domain_tag,
                .index_key.description  = description,
                .index_key.desc_len     = strlen(description),
                .cred                   = current_cred(),
                .match_data.raw_data    = description,
                .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
                .flags                  = (KEYRING_SEARCH_DO_STATE_CHECK |
-                                          KEYRING_SEARCH_SKIP_EXPIRED),
+                                          KEYRING_SEARCH_SKIP_EXPIRED |
+                                          KEYRING_SEARCH_RECURSE),
        };
        struct key *key;
        key_ref_t key_ref;
@@@ -663,9 -677,10 +673,10 @@@ int wait_for_key_construction(struct ke
  EXPORT_SYMBOL(wait_for_key_construction);
  
  /**
-  * request_key - Request a key and wait for construction
+  * request_key_tag - Request a key and wait for construction
   * @type: Type of key.
   * @description: The searchable description of the key.
+  * @domain_tag: The domain in which the key operates.
   * @callout_info: The data to pass to the instantiation upcall (or NULL).
   *
   * As for request_key_and_link() except that it does not add the returned key
   * Furthermore, it then works as wait_for_key_construction() to wait for the
   * completion of keys undergoing construction with a non-interruptible wait.
   */
- struct key *request_key(struct key_type *type,
-                       const char *description,
-                       const char *callout_info)
+ struct key *request_key_tag(struct key_type *type,
+                           const char *description,
+                           struct key_tag *domain_tag,
+                           const char *callout_info)
  {
        struct key *key;
        size_t callout_len = 0;
  
        if (callout_info)
                callout_len = strlen(callout_info);
-       key = request_key_and_link(type, description, callout_info, callout_len,
+       key = request_key_and_link(type, description, domain_tag,
+                                  callout_info, callout_len,
                                   NULL, NULL, KEY_ALLOC_IN_QUOTA);
        if (!IS_ERR(key)) {
                ret = wait_for_key_construction(key, false);
        }
        return key;
  }
- EXPORT_SYMBOL(request_key);
+ EXPORT_SYMBOL(request_key_tag);
  
  /**
   * request_key_with_auxdata - Request a key with auxiliary data for the upcaller
   * @type: The type of key we want.
   * @description: The searchable description of the key.
+  * @domain_tag: The domain in which the key operates.
   * @callout_info: The data to pass to the instantiation upcall (or NULL).
   * @callout_len: The length of callout_info.
   * @aux: Auxiliary data for the upcall.
   */
  struct key *request_key_with_auxdata(struct key_type *type,
                                     const char *description,
+                                    struct key_tag *domain_tag,
                                     const void *callout_info,
                                     size_t callout_len,
                                     void *aux)
        struct key *key;
        int ret;
  
-       key = request_key_and_link(type, description, callout_info, callout_len,
+       key = request_key_and_link(type, description, domain_tag,
+                                  callout_info, callout_len,
                                   aux, NULL, KEY_ALLOC_IN_QUOTA);
        if (!IS_ERR(key)) {
                ret = wait_for_key_construction(key, false);
@@@ -739,6 -759,7 +755,7 @@@ EXPORT_SYMBOL(request_key_with_auxdata)
   * request_key_rcu - Request key from RCU-read-locked context
   * @type: The type of key we want.
   * @description: The name of the key we want.
+  * @domain_tag: The domain in which the key operates.
   *
   * Request a key from a context that we may not sleep in (such as RCU-mode
   * pathwalk).  Keys under construction are ignored.
   * Return a pointer to the found key if successful, -ENOKEY if we couldn't find
   * a key or some other error if the key found was unsuitable or inaccessible.
   */
- struct key *request_key_rcu(struct key_type *type, const char *description)
+ struct key *request_key_rcu(struct key_type *type,
+                           const char *description,
+                           struct key_tag *domain_tag)
  {
        struct keyring_search_context ctx = {
                .index_key.type         = type,
+               .index_key.domain_tag   = domain_tag,
                .index_key.description  = description,
                .index_key.desc_len     = strlen(description),
                .cred                   = current_cred(),
index 5456c0c72857f0fec7f3753e332fa7cb5dca8c3d,f613987e8a63091729adf1adbdbc76b4846ac08e..e73ec040e2509494d3d123ad8c47419b747a33f7
@@@ -1,9 -1,13 +1,9 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /* Request key authorisation token key definition.
   *
   * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells ([email protected])
   *
 - * 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.
 - *
   * See Documentation/security/keys/request-key.rst
   */
  
@@@ -248,7 -252,8 +248,8 @@@ struct key *key_get_instantiation_authk
                .match_data.cmp         = key_default_cmp,
                .match_data.raw_data    = description,
                .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
-               .flags                  = KEYRING_SEARCH_DO_STATE_CHECK,
+               .flags                  = (KEYRING_SEARCH_DO_STATE_CHECK |
+                                          KEYRING_SEARCH_RECURSE),
        };
        struct key *authkey;
        key_ref_t authkey_ref;
This page took 0.188744 seconds and 4 git commands to generate.