diff options
| author | David Howells <dhowells@redhat.com> | 2013-09-24 05:35:18 -0400 |
|---|---|---|
| committer | David Howells <dhowells@redhat.com> | 2013-09-24 05:35:18 -0400 |
| commit | b2a4df200d570b2c33a57e1ebfa5896e4bc81b69 (patch) | |
| tree | 7fa48ae3c5ecff90d6d1f662fd91af5ddf74d56d | |
| parent | 3cb989501c2688cacbb7dc4b0d353faf838f53a1 (diff) | |
KEYS: Expand the capacity of a keyring
Expand the capacity of a keyring to be able to hold a lot more keys by using
the previously added associative array implementation. Currently the maximum
capacity is:
(PAGE_SIZE - sizeof(header)) / sizeof(struct key *)
which, on a 64-bit system, is a little more 500. However, since this is being
used for the NFS uid mapper, we need more than that. The new implementation
gives us effectively unlimited capacity.
With some alterations, the keyutils testsuite runs successfully to completion
after this patch is applied. The alterations are because (a) keyrings that
are simply added to no longer appear ordered and (b) some of the errors have
changed a bit.
Signed-off-by: David Howells <dhowells@redhat.com>
| -rw-r--r-- | include/keys/keyring-type.h | 17 | ||||
| -rw-r--r-- | include/linux/key.h | 13 | ||||
| -rw-r--r-- | lib/assoc_array.c | 1 | ||||
| -rw-r--r-- | security/keys/Kconfig | 1 | ||||
| -rw-r--r-- | security/keys/gc.c | 33 | ||||
| -rw-r--r-- | security/keys/internal.h | 17 | ||||
| -rw-r--r-- | security/keys/key.c | 35 | ||||
| -rw-r--r-- | security/keys/keyring.c | 1436 | ||||
| -rw-r--r-- | security/keys/request_key.c | 12 |
9 files changed, 803 insertions, 762 deletions
diff --git a/include/keys/keyring-type.h b/include/keys/keyring-type.h index cf49159b0e3a..fca5c62340a4 100644 --- a/include/keys/keyring-type.h +++ b/include/keys/keyring-type.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* Keyring key type | 1 | /* Keyring key type |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2008, 2013 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -13,19 +13,6 @@ | |||
| 13 | #define _KEYS_KEYRING_TYPE_H | 13 | #define _KEYS_KEYRING_TYPE_H |
| 14 | 14 | ||
| 15 | #include <linux/key.h> | 15 | #include <linux/key.h> |
| 16 | #include <linux/rcupdate.h> | 16 | #include <linux/assoc_array.h> |
| 17 | |||
| 18 | /* | ||
| 19 | * the keyring payload contains a list of the keys to which the keyring is | ||
| 20 | * subscribed | ||
| 21 | */ | ||
| 22 | struct keyring_list { | ||
| 23 | struct rcu_head rcu; /* RCU deletion hook */ | ||
| 24 | unsigned short maxkeys; /* max keys this list can hold */ | ||
| 25 | unsigned short nkeys; /* number of keys currently held */ | ||
| 26 | unsigned short delkey; /* key to be unlinked by RCU */ | ||
| 27 | struct key __rcu *keys[0]; | ||
| 28 | }; | ||
| 29 | |||
| 30 | 17 | ||
| 31 | #endif /* _KEYS_KEYRING_TYPE_H */ | 18 | #endif /* _KEYS_KEYRING_TYPE_H */ |
diff --git a/include/linux/key.h b/include/linux/key.h index ef596c7af585..2417f789d29b 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/sysctl.h> | 22 | #include <linux/sysctl.h> |
| 23 | #include <linux/rwsem.h> | 23 | #include <linux/rwsem.h> |
| 24 | #include <linux/atomic.h> | 24 | #include <linux/atomic.h> |
| 25 | #include <linux/assoc_array.h> | ||
| 25 | 26 | ||
| 26 | #ifdef __KERNEL__ | 27 | #ifdef __KERNEL__ |
| 27 | #include <linux/uidgid.h> | 28 | #include <linux/uidgid.h> |
| @@ -196,11 +197,13 @@ struct key { | |||
| 196 | * whatever | 197 | * whatever |
| 197 | */ | 198 | */ |
| 198 | union { | 199 | union { |
| 199 | unsigned long value; | 200 | union { |
| 200 | void __rcu *rcudata; | 201 | unsigned long value; |
| 201 | void *data; | 202 | void __rcu *rcudata; |
| 202 | struct keyring_list __rcu *subscriptions; | 203 | void *data; |
| 203 | } payload; | 204 | } payload; |
| 205 | struct assoc_array keys; | ||
| 206 | }; | ||
| 204 | }; | 207 | }; |
| 205 | 208 | ||
| 206 | extern struct key *key_alloc(struct key_type *type, | 209 | extern struct key *key_alloc(struct key_type *type, |
diff --git a/lib/assoc_array.c b/lib/assoc_array.c index a0952818f938..17edeaf19180 100644 --- a/lib/assoc_array.c +++ b/lib/assoc_array.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | //#define DEBUG | 13 | //#define DEBUG |
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/err.h> | ||
| 15 | #include <linux/assoc_array_priv.h> | 16 | #include <linux/assoc_array_priv.h> |
| 16 | 17 | ||
| 17 | /* | 18 | /* |
diff --git a/security/keys/Kconfig b/security/keys/Kconfig index a90d6d300dbd..15e0dfe8c80f 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | config KEYS | 5 | config KEYS |
| 6 | bool "Enable access key retention support" | 6 | bool "Enable access key retention support" |
| 7 | select ASSOCIATIVE_ARRAY | ||
| 7 | help | 8 | help |
| 8 | This option provides support for retaining authentication tokens and | 9 | This option provides support for retaining authentication tokens and |
| 9 | access keys in the kernel. | 10 | access keys in the kernel. |
diff --git a/security/keys/gc.c b/security/keys/gc.c index d67c97bb1025..cce621c33dce 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
| @@ -130,6 +130,13 @@ void key_gc_keytype(struct key_type *ktype) | |||
| 130 | kleave(""); | 130 | kleave(""); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static int key_gc_keyring_func(const void *object, void *iterator_data) | ||
| 134 | { | ||
| 135 | const struct key *key = object; | ||
| 136 | time_t *limit = iterator_data; | ||
| 137 | return key_is_dead(key, *limit); | ||
| 138 | } | ||
| 139 | |||
| 133 | /* | 140 | /* |
| 134 | * Garbage collect pointers from a keyring. | 141 | * Garbage collect pointers from a keyring. |
| 135 | * | 142 | * |
| @@ -138,10 +145,9 @@ void key_gc_keytype(struct key_type *ktype) | |||
| 138 | */ | 145 | */ |
| 139 | static void key_gc_keyring(struct key *keyring, time_t limit) | 146 | static void key_gc_keyring(struct key *keyring, time_t limit) |
| 140 | { | 147 | { |
| 141 | struct keyring_list *klist; | 148 | int result; |
| 142 | int loop; | ||
| 143 | 149 | ||
| 144 | kenter("%x", key_serial(keyring)); | 150 | kenter("%x{%s}", keyring->serial, keyring->description ?: ""); |
| 145 | 151 | ||
| 146 | if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | | 152 | if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | |
| 147 | (1 << KEY_FLAG_REVOKED))) | 153 | (1 << KEY_FLAG_REVOKED))) |
| @@ -149,27 +155,17 @@ static void key_gc_keyring(struct key *keyring, time_t limit) | |||
| 149 | 155 | ||
| 150 | /* scan the keyring looking for dead keys */ | 156 | /* scan the keyring looking for dead keys */ |
| 151 | rcu_read_lock(); | 157 | rcu_read_lock(); |
| 152 | klist = rcu_dereference(keyring->payload.subscriptions); | 158 | result = assoc_array_iterate(&keyring->keys, |
| 153 | if (!klist) | 159 | key_gc_keyring_func, &limit); |
| 154 | goto unlock_dont_gc; | ||
| 155 | |||
| 156 | loop = klist->nkeys; | ||
| 157 | smp_rmb(); | ||
| 158 | for (loop--; loop >= 0; loop--) { | ||
| 159 | struct key *key = rcu_dereference(klist->keys[loop]); | ||
| 160 | if (key_is_dead(key, limit)) | ||
| 161 | goto do_gc; | ||
| 162 | } | ||
| 163 | |||
| 164 | unlock_dont_gc: | ||
| 165 | rcu_read_unlock(); | 160 | rcu_read_unlock(); |
| 161 | if (result == true) | ||
| 162 | goto do_gc; | ||
| 163 | |||
| 166 | dont_gc: | 164 | dont_gc: |
| 167 | kleave(" [no gc]"); | 165 | kleave(" [no gc]"); |
| 168 | return; | 166 | return; |
| 169 | 167 | ||
| 170 | do_gc: | 168 | do_gc: |
| 171 | rcu_read_unlock(); | ||
| 172 | |||
| 173 | keyring_gc(keyring, limit); | 169 | keyring_gc(keyring, limit); |
| 174 | kleave(" [gc]"); | 170 | kleave(" [gc]"); |
| 175 | } | 171 | } |
| @@ -392,7 +388,6 @@ found_unreferenced_key: | |||
| 392 | */ | 388 | */ |
| 393 | found_keyring: | 389 | found_keyring: |
| 394 | spin_unlock(&key_serial_lock); | 390 | spin_unlock(&key_serial_lock); |
| 395 | kdebug("scan keyring %d", key->serial); | ||
| 396 | key_gc_keyring(key, limit); | 391 | key_gc_keyring(key, limit); |
| 397 | goto maybe_resched; | 392 | goto maybe_resched; |
| 398 | 393 | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 73950bf8f875..581c6f688352 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -90,20 +90,23 @@ extern void key_type_put(struct key_type *ktype); | |||
| 90 | 90 | ||
| 91 | extern int __key_link_begin(struct key *keyring, | 91 | extern int __key_link_begin(struct key *keyring, |
| 92 | const struct keyring_index_key *index_key, | 92 | const struct keyring_index_key *index_key, |
| 93 | unsigned long *_prealloc); | 93 | struct assoc_array_edit **_edit); |
| 94 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); | 94 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); |
| 95 | extern void __key_link(struct key *keyring, struct key *key, | 95 | extern void __key_link(struct key *key, struct assoc_array_edit **_edit); |
| 96 | unsigned long *_prealloc); | ||
| 97 | extern void __key_link_end(struct key *keyring, | 96 | extern void __key_link_end(struct key *keyring, |
| 98 | const | ||
