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
commit3b6e4de05e9ee2e2f94e4a3fe14d945e2418d9a8 (patch)
treec31a08de17f1607b40358d4351b1f97d78520164
parent0f44e4d976f96c6439da0d6717238efa4b91196e (diff)
keys: Include target namespace in match criteria
Currently a key has a standard matching criteria of { type, description } and this is used to only allow keys with unique criteria in a keyring. This means, however, that you cannot have keys with the same type and description but a different target namespace in the same keyring. This is a potential problem for a containerised environment where, say, a container is made up of some parts of its mount space involving netfs superblocks from two different network namespaces. This is also a problem for shared system management keyrings such as the DNS records keyring or the NFS idmapper keyring that might contain keys from different network namespaces. Fix this by including a namespace component in a key's matching criteria. Keyring types are marked to indicate which, if any, namespace is relevant to keys of that type, and that namespace is set when the key is created from the current task's namespace set. The capability bit KEYCTL_CAPS1_NS_KEY_TAG is set if the kernel is employing this feature. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--include/linux/key.h10
-rw-r--r--include/uapi/linux/keyctl.h1
-rw-r--r--security/keys/gc.c2
-rw-r--r--security/keys/key.c1
-rw-r--r--security/keys/keyctl.c3
-rw-r--r--security/keys/keyring.c36
-rw-r--r--security/keys/persistent.c1
7 files changed, 50 insertions, 4 deletions
diff --git a/include/linux/key.h b/include/linux/key.h
index ae1177302d70..abc68555bac3 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -82,9 +82,16 @@ struct cred;
82 82
83struct key_type; 83struct key_type;
84struct key_owner; 84struct key_owner;
85struct key_tag;
85struct keyring_list; 86struct keyring_list;
86struct keyring_name; 87struct keyring_name;
87 88
89struct key_tag {
90 struct rcu_head rcu;
91 refcount_t usage;
92 bool removed; /* T when subject removed */
93};
94
88struct keyring_index_key { 95struct keyring_index_key {
89 /* [!] If this structure is altered, the union in struct key must change too! */ 96 /* [!] If this structure is altered, the union in struct key must change too! */
90 unsigned long hash; /* Hash value */ 97 unsigned long hash; /* Hash value */
@@ -101,6 +108,7 @@ struct keyring_index_key {
101 unsigned long x; 108 unsigned long x;
102 }; 109 };
103 struct key_type *type; 110 struct key_type *type;
111 struct key_tag *domain_tag; /* Domain of operation */
104 const char *description; 112 const char *description;
105}; 113};
106 114
@@ -218,6 +226,7 @@ struct key {
218 unsigned long hash; 226 unsigned long hash;
219 unsigned long len_desc; 227 unsigned long len_desc;
220 struct key_type *type; /* type of key */ 228 struct key_type *type; /* type of key */
229 struct key_tag *domain_tag; /* Domain of operation */
221 char *description; 230 char *description;
222 }; 231 };
223 }; 232 };
@@ -268,6 +277,7 @@ extern struct key *key_alloc(struct key_type *type,
268extern void key_revoke(struct key *key); 277extern void key_revoke(struct key *key);
269extern void key_invalidate(struct key *key); 278extern void key_invalidate(struct key *key);
270extern void key_put(struct key *key); 279extern void key_put(struct key *key);
280extern bool key_put_tag(struct key_tag *tag);
271 281
272static inline struct key *__key_get(struct key *key) 282static inline struct key *__key_get(struct key *key)
273{ 283{
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 35b405034674..ed3d5893830d 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -129,5 +129,6 @@ struct keyctl_pkey_params {
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#define KEYCTL_CAPS1_NS_KEYRING_NAME 0x01 /* Keyring names are per-user_namespace */
132#define KEYCTL_CAPS1_NS_KEY_TAG 0x02 /* Key indexing can include a namespace tag */
132 133
133#endif /* _LINUX_KEYCTL_H */ 134#endif /* _LINUX_KEYCTL_H */
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 634e96b380e8..83d279fb7793 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -154,7 +154,7 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
154 atomic_dec(&key->user->nikeys); 154 atomic_dec(&key->user->nikeys);
155 155
156 key_user_put(key->user); 156 key_user_put(key->user);
157 157 key_put_tag(key->domain_tag);
158 kfree(key->description); 158 kfree(key->description);
159 159
160 memzero_explicit(key, sizeof(*key)); 160 memzero_explicit(key, sizeof(*key));
diff --git a/security/keys/key.c b/security/keys/key.c
index 9d52f2472a09..85fdc2ea6c14 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -317,6 +317,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
317 goto security_error; 317 goto security_error;
318 318
319 /* publish the key by giving it a serial number */ 319 /* publish the key by giving it a serial number */
320 refcount_inc(&key->domain_tag->usage);
320 atomic_inc(&user->nkeys); 321 atomic_inc(&user->nkeys);
321 key_alloc_serial(key); 322 key_alloc_serial(key);
322 323
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 8a813220f269..4bb5781d3ddf 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -40,7 +40,8 @@ static const unsigned char keyrings_capabilities[2] = {
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 [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME |
44 KEYCTL_CAPS1_NS_KEY_TAG),
44}; 45};
45 46
46static int key_get_type_from_user(char *type, 47static int key_get_type_from_user(char *type,
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 3663e5168583..0da8fa282d56 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -175,6 +175,9 @@ static void hash_key_type_and_desc(struct keyring_index_key *index_key)
175 type = (unsigned long)index_key->type; 175 type = (unsigned long)index_key->type;
176 acc = mult_64x32_and_fold(type, desc_len + 13); 176 acc = mult_64x32_and_fold(type, desc_len + 13);
177 acc = mult_64x32_and_fold(acc, 9207); 177 acc = mult_64x32_and_fold(acc, 9207);
178 piece = (unsigned long)index_key->domain_tag;
179 acc = mult_64x32_and_fold(acc, piece);
180 acc = mult_64x32_and_fold(acc, 9207);
178 181
179 for (;;) { 182 for (;;) {
180 n = desc_len; 183 n = desc_len;
@@ -208,16 +211,36 @@ static void hash_key_type_and_desc(struct keyring_index_key *index_key)
208 211
209/* 212/*
210 * Finalise an index key to include a part of the description actually in the 213 * Finalise an index key to include a part of the description actually in the
211 * index key and to add in the hash too. 214 * index key, to set the domain tag and to calculate the hash.
212 */ 215 */
213void key_set_index_key(struct keyring_index_key *index_key) 216void key_set_index_key(struct keyring_index_key *index_key)
214{ 217{
218 static struct key_tag default_domain_tag = { .usage = REFCOUNT_INIT(1), };
215 size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc)); 219 size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
220
216 memcpy(index_key->desc, index_key->description, n); 221 memcpy(index_key->desc, index_key->description, n);
217 222
223 index_key->domain_tag = &default_domain_tag;
218 hash_key_type_and_desc(index_key); 224 hash_key_type_and_desc(index_key);
219} 225}
220 226
227/**
228 * key_put_tag - Release a ref on a tag.
229 * @tag: The tag to release.
230 *
231 * This releases a reference the given tag and returns true if that ref was the
232 * last one.
233 */
234bool key_put_tag(struct key_tag *tag)
235{
236 if (refcount_dec_and_test(&tag->usage)) {
237 kfree_rcu(tag, rcu);
238 return true;
239 }
240
241 return false;
242}
243
221/* 244/*
222 * Build the next index key chunk. 245 * Build the next index key chunk.
223 * 246 *
@@ -238,8 +261,10 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
238 return index_key->x; 261 return index_key->x;
239 case 2: 262 case 2:
240 return (unsigned long)index_key->type; 263 return (unsigned long)index_key->type;
264 case 3:
265 return (unsigned long)index_key->domain_tag;
241 default: 266 default:
242 level -= 3; 267 level -= 4;
243 if (desc_len <= sizeof(index_key->desc)) 268 if (desc_len <= sizeof(index_key->desc))
244 return 0; 269 return 0;
245 270
@@ -268,6 +293,7 @@ static bool keyring_compare_object(const void *object, const void *data)
268 const struct key *key = keyring_ptr_to_key(object); 293 const struct key *key = keyring_ptr_to_key(object);
269 294
270 return key->index_key.type == index_key->type && 295 return key->index_key.type == index_key->type &&
296 key->index_key.domain_tag == index_key->domain_tag &&
271 key->index_key.desc_len == index_key->desc_len && 297 key->index_key.desc_len == index_key->desc_len &&
272 memcmp(key->index_key.description, index_key->description, 298 memcmp(key->index_key.description, index_key->description,
273 index_key->desc_len) == 0; 299 index_key->desc_len) == 0;
@@ -309,6 +335,12 @@ static int keyring_diff_objects(const void *object, const void *data)
309 goto differ; 335 goto differ;
310 level += sizeof(unsigned long); 336 level += sizeof(unsigned long);
311 337
338 seg_a = (unsigned long)a->domain_tag;
339 seg_b = (unsigned long)b->domain_tag;
340 if ((seg_a ^ seg_b) != 0)
341 goto differ;
342 level += sizeof(unsigned long);
343
312 i = sizeof(a->desc); 344 i = sizeof(a->desc);
313 if (a->desc_len <= i) 345 if (a->desc_len <= i)
314 goto same; 346 goto same;
diff --git a/security/keys/persistent.c b/security/keys/persistent.c
index 90303fe4a394..9944d855a28d 100644
--- a/security/keys/persistent.c
+++ b/security/keys/persistent.c
@@ -84,6 +84,7 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
84 long ret; 84 long ret;
85 85
86 /* Look in the register if it exists */ 86 /* Look in the register if it exists */
87 memset(&index_key, 0, sizeof(index_key));
87 index_key.type = &key_type_keyring; 88 index_key.type = &key_type_keyring;
88 index_key.description = buf; 89 index_key.description = buf;
89 index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid)); 90 index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid));