summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-06-26 16:02:32 -0400
committerDavid Howells <dhowells@redhat.com>2019-06-26 16:02:32 -0400
commitb206f281d0ee14969878469816a69db22d5838e8 (patch)
tree56828bdaec25c05d6b4126196276bf969d056929
parentdcf49dbc8077e278ddd1bc7298abc781496e8a08 (diff)
keys: Namespace keyring names
Keyring names are held in a single global list that any process can pick from by means of keyctl_join_session_keyring (provided the keyring grants Search permission). This isn't very container friendly, however. Make the following changes: (1) Make default session, process and thread keyring names begin with a '.' instead of '_'. (2) Keyrings whose names begin with a '.' aren't added to the list. Such keyrings are system specials. (3) Replace the global list with per-user_namespace lists. A keyring adds its name to the list for the user_namespace that it is currently in. (4) When a user_namespace is deleted, it just removes itself from the keyring name list. The global keyring_name_lock is retained for accessing the name lists. This allows (4) to work. This can be tested by: # keyctl newring foo @s 995906392 # unshare -U $ keyctl show ... 995906392 --alswrv 65534 65534 \_ keyring: foo ... $ keyctl session foo Joined session keyring: 935622349 As can be seen, a new session keyring was created. The capability bit KEYCTL_CAPS1_NS_KEYRING_NAME is set if the kernel is employing this feature. Signed-off-by: David Howells <dhowells@redhat.com> cc: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--include/linux/key.h2
-rw-r--r--include/linux/user_namespace.h5
-rw-r--r--include/uapi/linux/keyctl.h1
-rw-r--r--kernel/user.c3
-rw-r--r--kernel/user_namespace.c7
-rw-r--r--security/keys/keyctl.c3
-rw-r--r--security/keys/keyring.c99
7 files changed, 60 insertions, 60 deletions
diff --git a/include/linux/key.h b/include/linux/key.h
index ff102731b3db..ae1177302d70 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -361,6 +361,7 @@ extern void key_set_timeout(struct key *, unsigned);
361 361
362extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, 362extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
363 key_perm_t perm); 363 key_perm_t perm);
364extern void key_free_user_ns(struct user_namespace *);
364 365
365/* 366/*
366 * The permissions required on a key that we're looking up. 367 * The permissions required on a key that we're looking up.
@@ -434,6 +435,7 @@ extern void key_init(void);
434#define key_fsuid_changed(c) do { } while(0) 435#define key_fsuid_changed(c) do { } while(0)
435#define key_fsgid_changed(c) do { } while(0) 436#define key_fsgid_changed(c) do { } while(0)
436#define key_init() do { } while(0) 437#define key_init() do { } while(0)
438#define key_free_user_ns(ns) do { } while(0)
437 439
438#endif /* CONFIG_KEYS */ 440#endif /* CONFIG_KEYS */
439#endif /* __KERNEL__ */ 441#endif /* __KERNEL__ */
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index d6b74b91096b..90457015fa3f 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -64,6 +64,11 @@ struct user_namespace {
64 struct ns_common ns; 64 struct ns_common ns;
65 unsigned long flags; 65 unsigned long flags;
66 66
67#ifdef CONFIG_KEYS
68 /* List of joinable keyrings in this namespace */
69 struct list_head keyring_name_list;
70#endif
71
67 /* Register of per-UID persistent keyrings for this namespace */ 72 /* Register of per-UID persistent keyrings for this namespace */
68#ifdef CONFIG_PERSISTENT_KEYRINGS 73#ifdef CONFIG_PERSISTENT_KEYRINGS
69 struct key *persistent_keyring_register; 74 struct key *persistent_keyring_register;
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 551b5814f53e..35b405034674 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -128,5 +128,6 @@ struct keyctl_pkey_params {
128#define KEYCTL_CAPS0_INVALIDATE 0x20 /* KEYCTL_INVALIDATE supported */ 128#define KEYCTL_CAPS0_INVALIDATE 0x20 /* KEYCTL_INVALIDATE supported */
129#define KEYCTL_CAPS0_RESTRICT_KEYRING 0x40 /* KEYCTL_RESTRICT_KEYRING supported */ 129#define KEYCTL_CAPS0_RESTRICT_KEYRING 0x40 /* KEYCTL_RESTRICT_KEYRING supported */
130#define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */ 130#define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */
131#define KEYCTL_CAPS1_NS_KEYRING_NAME 0x01 /* Keyring names are per-user_namespace */
131 132
132#endif /* _LINUX_KEYCTL_H */ 133#endif /* _LINUX_KEYCTL_H */
diff --git a/kernel/user.c b/kernel/user.c
index 88b834f0eebc..50979fd1b7aa 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -62,6 +62,9 @@ struct user_namespace init_user_ns = {
62 .ns.ops = &userns_operations, 62 .ns.ops = &userns_operations,
63#endif 63#endif
64 .flags = USERNS_INIT_FLAGS, 64 .flags = USERNS_INIT_FLAGS,
65#ifdef CONFIG_KEYS
66 .keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
67#endif
65#ifdef CONFIG_PERSISTENT_KEYRINGS 68#ifdef CONFIG_PERSISTENT_KEYRINGS
66 .persistent_keyring_register_sem = 69 .persistent_keyring_register_sem =
67 __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), 70 __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 923414a246e9..bda6e890ad88 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -133,6 +133,9 @@ int create_user_ns(struct cred *new)
133 ns->flags = parent_ns->flags; 133 ns->flags = parent_ns->flags;
134 mutex_unlock(&userns_state_mutex); 134 mutex_unlock(&userns_state_mutex);
135 135
136#ifdef CONFIG_KEYS
137 INIT_LIST_HEAD(&ns->keyring_name_list);
138#endif
136#ifdef CONFIG_PERSISTENT_KEYRINGS 139#ifdef CONFIG_PERSISTENT_KEYRINGS
137 init_rwsem(&ns->persistent_keyring_register_sem); 140 init_rwsem(&ns->persistent_keyring_register_sem);
138#endif 141#endif
@@ -196,9 +199,7 @@ static void free_user_ns(struct work_struct *work)
196 kfree(ns->projid_map.reverse); 199 kfree(ns->projid_map.reverse);
197 } 200 }
198 retire_userns_sysctls(ns); 201 retire_userns_sysctls(ns);
199#ifdef CONFIG_PERSISTENT_KEYRINGS 202 key_free_user_ns(ns);
200 key_put(ns->persistent_keyring_register);
201#endif
202 ns_free_inum(&ns->ns); 203 ns_free_inum(&ns->ns);
203 kmem_cache_free(user_ns_cachep, ns); 204 kmem_cache_free(user_ns_cachep, ns);
204 dec_user_namespaces(ucounts); 205 dec_user_namespaces(ucounts);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 169409b611b0..8a813220f269 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -30,7 +30,7 @@
30 30
31#define KEY_MAX_DESC_SIZE 4096 31#define KEY_MAX_DESC_SIZE 4096
32 32
33static const unsigned char keyrings_capabilities[1] = { 33static const unsigned char keyrings_capabilities[2] = {
34 [0] = (KEYCTL_CAPS0_CAPABILITIES | 34 [0] = (KEYCTL_CAPS0_CAPABILITIES |
35 (IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS) ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) | 35 (IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS) ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) |
36 (IS_ENABLED(CONFIG_KEY_DH_OPERATIONS) ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) | 36 (IS_ENABLED(CONFIG_KEY_DH_OPERATIONS) ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) |
@@ -40,6 +40,7 @@ static const unsigned char keyrings_capabilities[1] = {
40 KEYCTL_CAPS0_RESTRICT_KEYRING | 40 KEYCTL_CAPS0_RESTRICT_KEYRING |
41 KEYCTL_CAPS0_MOVE 41 KEYCTL_CAPS0_MOVE
42 ), 42 ),
43 [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME),
43}; 44};
44 45
45static int key_get_type_from_user(char *type, 46static int key_get_type_from_user(char *type,
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 20891cd198f0..fe851292509e 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -16,6 +16,7 @@
16#include <linux/security.h> 16#include <linux/security.h>
17#include <linux/seq_file.h> 17#include <linux/seq_file.h>
18#include <linux/err.h> 18#include <linux/err.h>
19#include <linux/user_namespace.h>
19#include <keys/keyring-type.h> 20#include <keys/keyring-type.h>
20#include <keys/user-type.h> 21#include <keys/user-type.h>
21#include <linux/assoc_array_priv.h> 22#include <linux/assoc_array_priv.h>
@@ -29,11 +30,6 @@
29#define KEYRING_SEARCH_MAX_DEPTH 6 30#define KEYRING_SEARCH_MAX_DEPTH 6
30 31
31/* 32/*
32 * We keep all named keyrings in a hash to speed looking them up.
33 */
34#define KEYRING_NAME_HASH_SIZE (1 << 5)
35
36/*
37 * We mark pointers we pass to the associative array with bit 1 set if 33 * We mark pointers we pass to the associative array with bit 1 set if
38 * they're keyrings and clear otherwise. 34 * they're keyrings and clear otherwise.
39 */ 35 */
@@ -55,17 +51,20 @@ static inline void *keyring_key_to_ptr(struct key *key)
55 return key; 51 return key;
56} 52}
57 53
58static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE];
59static DEFINE_RWLOCK(keyring_name_lock); 54static DEFINE_RWLOCK(keyring_name_lock);
60 55
61static inline unsigned keyring_hash(const char *desc) 56/*
57 * Clean up the bits of user_namespace that belong to us.
58 */
59void key_free_user_ns(struct user_namespace *ns)
62{ 60{
63 unsigned bucket = 0; 61 write_lock(&keyring_name_lock);
64 62 list_del_init(&ns->keyring_name_list);
65 for (; *desc; desc++) 63 write_unlock(&keyring_name_lock);
66 bucket += (unsigned char)*desc;
67 64
68 return bucket & (KEYRING_NAME_HASH_SIZE - 1); 65#ifdef CONFIG_PERSISTENT_KEYRINGS
66 key_put(ns->persistent_keyring_register);
67#endif
69} 68}
70 69
71/* 70/*
@@ -104,23 +103,17 @@ static DEFINE_MUTEX(keyring_serialise_link_lock);
104 103
105/* 104/*
106 * Publish the name of a keyring so that it can be found by name (if it has 105 * Publish the name of a keyring so that it can be found by name (if it has
107 * one). 106 * one and it doesn't begin with a dot).
108 */ 107 */
109static void keyring_publish_name(struct key *keyring) 108static void keyring_publish_name(struct key *keyring)
110{ 109{
111 int bucket; 110 struct user_namespace *ns = current_user_ns();
112
113 if (keyring->description) {
114 bucket = keyring_hash(keyring->description);
115 111
112 if (keyring->description &&
113 keyring->description[0] &&
114 keyring->description[0] != '.') {
116 write_lock(&keyring_name_lock); 115 write_lock(&keyring_name_lock);
117 116 list_add_tail(&keyring->name_link, &ns->keyring_name_list);
118 if (!keyring_name_hash[bucket].next)
119 INIT_LIST_HEAD(&keyring_name_hash[bucket]);
120
121 list_add_tail(&keyring->name_link,
122 &keyring_name_hash[bucket]);
123
124 write_unlock(&keyring_name_lock); 117 write_unlock(&keyring_name_lock);
125 } 118 }
126} 119}
@@ -1097,50 +1090,44 @@ found:
1097 */ 1090 */
1098struct key *find_keyring_by_name(const char *name, bool uid_keyring) 1091struct key *find_keyring_by_name(const char *name, bool uid_keyring)
1099{ 1092{
1093 struct user_namespace *ns = current_user_ns();
1100 struct key *keyring; 1094 struct key *keyring;
1101 int bucket;
1102 1095
1103 if (!name) 1096 if (!name)
1104 return ERR_PTR(-EINVAL); 1097 return ERR_PTR(-EINVAL);
1105 1098
1106 bucket = keyring_hash(name);
1107
1108 read_lock(&keyring_name_lock); 1099 read_lock(&keyring_name_lock);
1109 1100
1110 if (keyring_name_hash[bucket].next) { 1101 /* Search this hash bucket for a keyring with a matching name that
1111 /* search this hash bucket for a keyring with a matching name 1102 * grants Search permission and that hasn't been revoked
1112 * that's readable and that hasn't been revoked */ 1103 */
1113 list_for_each_entry(keyring, 1104 list_for_each_entry(keyring, &ns->keyring_name_list, name_link) {
1114 &keyring_name_hash[bucket], 1105 if (!kuid_has_mapping(ns, keyring->user->uid))
1115 name_link 1106 continue;
1116 ) {
1117 if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
1118 continue;
1119
1120 if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1121 continue;
1122 1107
1123 if (strcmp(keyring->description, name) != 0) 1108 if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1124 continue; 1109 continue;
1125 1110
1126 if (uid_keyring) { 1111 if (strcmp(keyring->description, name) != 0)
1127 if (!test_bit(KEY_FLAG_UID_KEYRING, 1112 continue;
1128 &keyring->flags))
1129 continue;
1130 } else {
1131 if (key_permission(make_key_ref(keyring, 0),
1132 KEY_NEED_SEARCH) < 0)
1133 continue;
1134 }
1135 1113
1136 /* we've got a match but we might end up racing with 1114 if (uid_keyring) {
1137 * key_cleanup() if the keyring is currently 'dead' 1115 if (!test_bit(KEY_FLAG_UID_KEYRING,
1138 * (ie. it has a zero usage count) */ 1116 &keyring->flags))
1139 if (!refcount_inc_not_zero(&keyring->usage)) 1117 continue;
1118 } else {
1119 if (key_permission(make_key_ref(keyring, 0),
1120 KEY_NEED_SEARCH) < 0)
1140 continue; 1121 continue;
1141 keyring->last_used_at = ktime_get_real_seconds();
1142 goto out;
1143 } 1122 }
1123
1124 /* we've got a match but we might end up racing with
1125 * key_cleanup() if the keyring is currently 'dead'
1126 * (ie. it has a zero usage count) */
1127 if (!refcount_inc_not_zero(&keyring->usage))
1128 continue;
1129 keyring->last_used_at = ktime_get_real_seconds();
1130 goto out;
1144 } 1131 }
1145 1132
1146 keyring = ERR_PTR(-ENOKEY); 1133 keyring = ERR_PTR(-ENOKEY);