diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/Kconfig | 71 | ||||
-rw-r--r-- | security/keys/Makefile | 12 | ||||
-rw-r--r-- | security/keys/compat.c | 3 | ||||
-rw-r--r-- | security/keys/gc.c | 94 | ||||
-rw-r--r-- | security/keys/internal.h | 15 | ||||
-rw-r--r-- | security/keys/key.c | 25 | ||||
-rw-r--r-- | security/keys/keyctl.c | 34 | ||||
-rw-r--r-- | security/keys/keyring.c | 167 | ||||
-rw-r--r-- | security/keys/permission.c | 43 | ||||
-rw-r--r-- | security/keys/proc.c | 3 | ||||
-rw-r--r-- | security/keys/process_keys.c | 2 |
11 files changed, 345 insertions, 124 deletions
diff --git a/security/keys/Kconfig b/security/keys/Kconfig new file mode 100644 index 000000000000..a90d6d300dbd --- /dev/null +++ b/security/keys/Kconfig | |||
@@ -0,0 +1,71 @@ | |||
1 | # | ||
2 | # Key management configuration | ||
3 | # | ||
4 | |||
5 | config KEYS | ||
6 | bool "Enable access key retention support" | ||
7 | help | ||
8 | This option provides support for retaining authentication tokens and | ||
9 | access keys in the kernel. | ||
10 | |||
11 | It also includes provision of methods by which such keys might be | ||
12 | associated with a process so that network filesystems, encryption | ||
13 | support and the like can find them. | ||
14 | |||
15 | Furthermore, a special type of key is available that acts as keyring: | ||
16 | a searchable sequence of keys. Each process is equipped with access | ||
17 | to five standard keyrings: UID-specific, GID-specific, session, | ||
18 | process and thread. | ||
19 | |||
20 | If you are unsure as to whether this is required, answer N. | ||
21 | |||
22 | config TRUSTED_KEYS | ||
23 | tristate "TRUSTED KEYS" | ||
24 | depends on KEYS && TCG_TPM | ||
25 | select CRYPTO | ||
26 | select CRYPTO_HMAC | ||
27 | select CRYPTO_SHA1 | ||
28 | help | ||
29 | This option provides support for creating, sealing, and unsealing | ||
30 | keys in the kernel. Trusted keys are random number symmetric keys, | ||
31 | generated and RSA-sealed by the TPM. The TPM only unseals the keys, | ||
32 | if the boot PCRs and other criteria match. Userspace will only ever | ||
33 | see encrypted blobs. | ||
34 | |||
35 | If you are unsure as to whether this is required, answer N. | ||
36 | |||
37 | config ENCRYPTED_KEYS | ||
38 | tristate "ENCRYPTED KEYS" | ||
39 | depends on KEYS | ||
40 | select CRYPTO | ||
41 | select CRYPTO_HMAC | ||
42 | select CRYPTO_AES | ||
43 | select CRYPTO_CBC | ||
44 | select CRYPTO_SHA256 | ||
45 | select CRYPTO_RNG | ||
46 | help | ||
47 | This option provides support for create/encrypting/decrypting keys | ||
48 | in the kernel. Encrypted keys are kernel generated random numbers, | ||
49 | which are encrypted/decrypted with a 'master' symmetric key. The | ||
50 | 'master' key can be either a trusted-key or user-key type. | ||
51 | Userspace only ever sees/stores encrypted blobs. | ||
52 | |||
53 | If you are unsure as to whether this is required, answer N. | ||
54 | |||
55 | config KEYS_DEBUG_PROC_KEYS | ||
56 | bool "Enable the /proc/keys file by which keys may be viewed" | ||
57 | depends on KEYS | ||
58 | help | ||
59 | This option turns on support for the /proc/keys file - through which | ||
60 | can be listed all the keys on the system that are viewable by the | ||
61 | reading process. | ||
62 | |||
63 | The only keys included in the list are those that grant View | ||
64 | permission to the reading process whether or not it possesses them. | ||
65 | Note that LSM security checks are still performed, and may further | ||
66 | filter out keys that the current process is not authorised to view. | ||
67 | |||
68 | Only key attributes are listed here; key payloads are not included in | ||
69 | the resulting table. | ||
70 | |||
71 | If you are unsure as to whether this is required, answer N. | ||
diff --git a/security/keys/Makefile b/security/keys/Makefile index a56f1ffdc64d..504aaa008388 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -2,6 +2,9 @@ | |||
2 | # Makefile for key management | 2 | # Makefile for key management |
3 | # | 3 | # |
4 | 4 | ||
5 | # | ||
6 | # Core | ||
7 | # | ||
5 | obj-y := \ | 8 | obj-y := \ |
6 | gc.o \ | 9 | gc.o \ |
7 | key.o \ | 10 | key.o \ |
@@ -12,9 +15,12 @@ obj-y := \ | |||
12 | request_key.o \ | 15 | request_key.o \ |
13 | request_key_auth.o \ | 16 | request_key_auth.o \ |
14 | user_defined.o | 17 | user_defined.o |
15 | |||
16 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||
17 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | ||
18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
19 | obj-$(CONFIG_PROC_FS) += proc.o | 19 | obj-$(CONFIG_PROC_FS) += proc.o |
20 | obj-$(CONFIG_SYSCTL) += sysctl.o | 20 | obj-$(CONFIG_SYSCTL) += sysctl.o |
21 | |||
22 | # | ||
23 | # Key types | ||
24 | # | ||
25 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||
26 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | ||
diff --git a/security/keys/compat.c b/security/keys/compat.c index 4c48e13448f8..fab4f8dda6c6 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -135,6 +135,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
135 | return compat_keyctl_instantiate_key_iov( | 135 | return compat_keyctl_instantiate_key_iov( |
136 | arg2, compat_ptr(arg3), arg4, arg5); | 136 | arg2, compat_ptr(arg3), arg4, arg5); |
137 | 137 | ||
138 | case KEYCTL_INVALIDATE: | ||
139 | return keyctl_invalidate_key(arg2); | ||
140 | |||
138 | default: | 141 | default: |
139 | return -EOPNOTSUPP; | 142 | return -EOPNOTSUPP; |
140 | } | 143 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c index a42b45531aac..61ab7c82ebb1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -72,6 +72,15 @@ void key_schedule_gc(time_t gc_at) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Schedule a dead links collection run. | ||
76 | */ | ||
77 | void key_schedule_gc_links(void) | ||
78 | { | ||
79 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | ||
80 | queue_work(system_nrt_wq, &key_gc_work); | ||
81 | } | ||
82 | |||
83 | /* | ||
75 | * Some key's cleanup time was met after it expired, so we need to get the | 84 | * Some key's cleanup time was met after it expired, so we need to get the |
76 | * reaper to go through a cycle finding expired keys. | 85 | * reaper to go through a cycle finding expired keys. |
77 | */ | 86 | */ |
@@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data) | |||
79 | { | 88 | { |
80 | kenter(""); | 89 | kenter(""); |
81 | key_gc_next_run = LONG_MAX; | 90 | key_gc_next_run = LONG_MAX; |
82 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | 91 | key_schedule_gc_links(); |
83 | queue_work(system_nrt_wq, &key_gc_work); | ||
84 | } | 92 | } |
85 | 93 | ||
86 | /* | 94 | /* |
@@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype) | |||
131 | static void key_gc_keyring(struct key *keyring, time_t limit) | 139 | static void key_gc_keyring(struct key *keyring, time_t limit) |
132 | { | 140 | { |
133 | struct keyring_list *klist; | 141 | struct keyring_list *klist; |
134 | struct key *key; | ||
135 | int loop; | 142 | int loop; |
136 | 143 | ||
137 | kenter("%x", key_serial(keyring)); | 144 | kenter("%x", key_serial(keyring)); |
138 | 145 | ||
139 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 146 | if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | |
147 | (1 << KEY_FLAG_REVOKED))) | ||
140 | goto dont_gc; | 148 | goto dont_gc; |
141 | 149 | ||
142 | /* scan the keyring looking for dead keys */ | 150 | /* scan the keyring looking for dead keys */ |
@@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit) | |||
148 | loop = klist->nkeys; | 156 | loop = klist->nkeys; |
149 | smp_rmb(); | 157 | smp_rmb(); |
150 | for (loop--; loop >= 0; loop--) { | 158 | for (loop--; loop >= 0; loop--) { |
151 | key = klist->keys[loop]; | 159 | struct key *key = rcu_dereference(klist->keys[loop]); |
152 | if (test_bit(KEY_FLAG_DEAD, &key->flags) || | 160 | if (key_is_dead(key, limit)) |
153 | (key->expiry > 0 && key->expiry <= limit)) | ||
154 | goto do_gc; | 161 | goto do_gc; |
155 | } | 162 | } |
156 | 163 | ||
@@ -168,38 +175,45 @@ do_gc: | |||
168 | } | 175 | } |
169 | 176 | ||
170 | /* | 177 | /* |
171 | * Garbage collect an unreferenced, detached key | 178 | * Garbage collect a list of unreferenced, detached keys |
172 | */ | 179 | */ |
173 | static noinline void key_gc_unused_key(struct key *key) | 180 | static noinline void key_gc_unused_keys(struct list_head *keys) |
174 | { | 181 | { |
175 | key_check(key); | 182 | while (!list_empty(keys)) { |
176 | 183 | struct key *key = | |
177 | security_key_free(key); | 184 | list_entry(keys->next, struct key, graveyard_link); |
178 | 185 | list_del(&key->graveyard_link); | |
179 | /* deal with the user's key tracking and quota */ | 186 | |
180 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 187 | kdebug("- %u", key->serial); |
181 | spin_lock(&key->user->lock); | 188 | key_check(key); |
182 | key->user->qnkeys--; | 189 | |
183 | key->user->qnbytes -= key->quotalen; | 190 | security_key_free(key); |
184 | spin_unlock(&key->user->lock); | 191 | |
185 | } | 192 | /* deal with the user's key tracking and quota */ |
193 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
194 | spin_lock(&key->user->lock); | ||
195 | key->user->qnkeys--; | ||
196 | key->user->qnbytes -= key->quotalen; | ||
197 | spin_unlock(&key->user->lock); | ||
198 | } | ||
186 | 199 | ||
187 | atomic_dec(&key->user->nkeys); | 200 | atomic_dec(&key->user->nkeys); |
188 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 201 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
189 | atomic_dec(&key->user->nikeys); | 202 | atomic_dec(&key->user->nikeys); |
190 | 203 | ||
191 | key_user_put(key->user); | 204 | key_user_put(key->user); |
192 | 205 | ||
193 | /* now throw away the key memory */ | 206 | /* now throw away the key memory */ |
194 | if (key->type->destroy) | 207 | if (key->type->destroy) |
195 | key->type->destroy(key); | 208 | key->type->destroy(key); |
196 | 209 | ||
197 | kfree(key->description); | 210 | kfree(key->description); |
198 | 211 | ||
199 | #ifdef KEY_DEBUGGING | 212 | #ifdef KEY_DEBUGGING |
200 | key->magic = KEY_DEBUG_MAGIC_X; | 213 | key->magic = KEY_DEBUG_MAGIC_X; |
201 | #endif | 214 | #endif |
202 | kmem_cache_free(key_jar, key); | 215 | kmem_cache_free(key_jar, key); |
216 | } | ||
203 | } | 217 | } |
204 | 218 | ||
205 | /* | 219 | /* |
@@ -211,6 +225,7 @@ static noinline void key_gc_unused_key(struct key *key) | |||
211 | */ | 225 | */ |
212 | static void key_garbage_collector(struct work_struct *work) | 226 | static void key_garbage_collector(struct work_struct *work) |
213 | { | 227 | { |
228 | static LIST_HEAD(graveyard); | ||
214 | static u8 gc_state; /* Internal persistent state */ | 229 | static u8 gc_state; /* Internal persistent state */ |
215 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ | 230 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ |
216 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ | 231 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ |
@@ -316,15 +331,22 @@ maybe_resched: | |||
316 | key_schedule_gc(new_timer); | 331 | key_schedule_gc(new_timer); |
317 | } | 332 | } |
318 | 333 | ||
319 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { | 334 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || |
320 | /* Make sure everyone revalidates their keys if we marked a | 335 | !list_empty(&graveyard)) { |
321 | * bunch as being dead and make sure all keyring ex-payloads | 336 | /* Make sure that all pending keyring payload destructions are |
322 | * are destroyed. | 337 | * fulfilled and that people aren't now looking at dead or |
338 | * dying keys that they don't have a reference upon or a link | ||
339 | * to. | ||
323 | */ | 340 | */ |
324 | kdebug("dead sync"); | 341 | kdebug("gc sync"); |
325 | synchronize_rcu(); | 342 | synchronize_rcu(); |
326 | } | 343 | } |
327 | 344 | ||
345 | if (!list_empty(&graveyard)) { | ||
346 | kdebug("gc keys"); | ||
347 | key_gc_unused_keys(&graveyard); | ||
348 | } | ||
349 | |||
328 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | | 350 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | |
329 | KEY_GC_REAPING_DEAD_2))) { | 351 | KEY_GC_REAPING_DEAD_2))) { |
330 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { | 352 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { |
@@ -359,7 +381,7 @@ found_unreferenced_key: | |||
359 | rb_erase(&key->serial_node, &key_serial_tree); | 381 | rb_erase(&key->serial_node, &key_serial_tree); |
360 | spin_unlock(&key_serial_lock); | 382 | spin_unlock(&key_serial_lock); |
361 | 383 | ||
362 | key_gc_unused_key(key); | 384 | list_add_tail(&key->graveyard_link, &graveyard); |
363 | gc_state |= KEY_GC_REAP_AGAIN; | 385 | gc_state |= KEY_GC_REAP_AGAIN; |
364 | goto maybe_resched; | 386 | goto maybe_resched; |
365 | 387 | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 65647f825584..f711b094ed41 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -152,7 +152,8 @@ extern long join_session_keyring(const char *name); | |||
152 | extern struct work_struct key_gc_work; | 152 | extern struct work_struct key_gc_work; |
153 | extern unsigned key_gc_delay; | 153 | extern unsigned key_gc_delay; |
154 | extern void keyring_gc(struct key *keyring, time_t limit); | 154 | extern void keyring_gc(struct key *keyring, time_t limit); |
155 | extern void key_schedule_gc(time_t expiry_at); | 155 | extern void key_schedule_gc(time_t gc_at); |
156 | extern void key_schedule_gc_links(void); | ||
156 | extern void key_gc_keytype(struct key_type *ktype); | 157 | extern void key_gc_keytype(struct key_type *ktype); |
157 | 158 | ||
158 | extern int key_task_permission(const key_ref_t key_ref, | 159 | extern int key_task_permission(const key_ref_t key_ref, |
@@ -197,6 +198,17 @@ extern struct key *request_key_auth_new(struct key *target, | |||
197 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | 198 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); |
198 | 199 | ||
199 | /* | 200 | /* |
201 | * Determine whether a key is dead. | ||
202 | */ | ||
203 | static inline bool key_is_dead(struct key *key, time_t limit) | ||
204 | { | ||
205 | return | ||
206 | key->flags & ((1 << KEY_FLAG_DEAD) | | ||
207 | (1 << KEY_FLAG_INVALIDATED)) || | ||
208 | (key->expiry > 0 && key->expiry <= limit); | ||
209 | } | ||
210 | |||
211 | /* | ||
200 | * keyctl() functions | 212 | * keyctl() functions |
201 | */ | 213 | */ |
202 | extern long keyctl_get_keyring_ID(key_serial_t, int); | 214 | extern long keyctl_get_keyring_ID(key_serial_t, int); |
@@ -225,6 +237,7 @@ extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); | |||
225 | extern long keyctl_instantiate_key_iov(key_serial_t, | 237 | extern long keyctl_instantiate_key_iov(key_serial_t, |
226 | const struct iovec __user *, | 238 | const struct iovec __user *, |
227 | unsigned, key_serial_t); | 239 | unsigned, key_serial_t); |
240 | extern long keyctl_invalidate_key(key_serial_t); | ||
228 | 241 | ||
229 | extern long keyctl_instantiate_key_common(key_serial_t, | 242 | extern long keyctl_instantiate_key_common(key_serial_t, |
230 | const struct iovec __user *, | 243 | const struct iovec __user *, |
diff --git a/security/keys/key.c b/security/keys/key.c index 06783cffb3af..c9bf66ac36e0 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -955,6 +955,28 @@ void key_revoke(struct key *key) | |||
955 | EXPORT_SYMBOL(key_revoke); | 955 | EXPORT_SYMBOL(key_revoke); |
956 | 956 | ||
957 | /** | 957 | /** |
958 | * key_invalidate - Invalidate a key. | ||
959 | * @key: The key to be invalidated. | ||
960 | * | ||
961 | * Mark a key as being invalidated and have it cleaned up immediately. The key | ||
962 | * is ignored by all searches and other operations from this point. | ||
963 | */ | ||
964 | void key_invalidate(struct key *key) | ||
965 | { | ||
966 | kenter("%d", key_serial(key)); | ||
967 | |||
968 | key_check(key); | ||
969 | |||
970 | if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { | ||
971 | down_write_nested(&key->sem, 1); | ||
972 | if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) | ||
973 | key_schedule_gc_links(); | ||
974 | up_write(&key->sem); | ||
975 | } | ||
976 | } | ||
977 | EXPORT_SYMBOL(key_invalidate); | ||
978 | |||
979 | /** | ||
958 | * register_key_type - Register a type of key. | 980 | * register_key_type - Register a type of key. |
959 | * @ktype: The new key type. | 981 | * @ktype: The new key type. |
960 | * | 982 | * |
@@ -980,6 +1002,8 @@ int register_key_type(struct key_type *ktype) | |||
980 | 1002 | ||
981 | /* store the type */ | 1003 | /* store the type */ |
982 | list_add(&ktype->link, &key_types_list); | 1004 | list_add(&ktype->link, &key_types_list); |
1005 | |||
1006 | pr_notice("Key type %s registered\n", ktype->name); | ||
983 | ret = 0; | 1007 | ret = 0; |
984 | 1008 | ||
985 | out: | 1009 | out: |
@@ -1002,6 +1026,7 @@ void unregister_key_type(struct key_type *ktype) | |||
1002 | list_del_init(&ktype->link); | 1026 | list_del_init(&ktype->link); |
1003 | downgrade_write(&key_types_sem); | 1027 | downgrade_write(&key_types_sem); |
1004 | key_gc_keytype(ktype); | 1028 | key_gc_keytype(ktype); |
1029 | pr_notice("Key type %s unregistered\n", ktype->name); | ||
1005 | up_read(&key_types_sem); | 1030 | up_read(&key_types_sem); |
1006 | } | 1031 | } |
1007 | EXPORT_SYMBOL(unregister_key_type); | 1032 | EXPORT_SYMBOL(unregister_key_type); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index fb767c6cd99f..ddb3e05bc5fc 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -375,6 +375,37 @@ error: | |||
375 | } | 375 | } |
376 | 376 | ||
377 | /* | 377 | /* |
378 | * Invalidate a key. | ||
379 | * | ||
380 | * The key must be grant the caller Invalidate permission for this to work. | ||
381 | * The key and any links to the key will be automatically garbage collected | ||
382 | * immediately. | ||
383 | * | ||
384 | * If successful, 0 is returned. | ||
385 | */ | ||
386 | long keyctl_invalidate_key(key_serial_t id) | ||
387 | { | ||
388 | key_ref_t key_ref; | ||
389 | long ret; | ||
390 | |||
391 | kenter("%d", id); | ||
392 | |||
393 | key_ref = lookup_user_key(id, 0, KEY_SEARCH); | ||
394 | if (IS_ERR(key_ref)) { | ||
395 | ret = PTR_ERR(key_ref); | ||
396 | goto error; | ||
397 | } | ||
398 | |||
399 | key_invalidate(key_ref_to_ptr(key_ref)); | ||
400 | ret = 0; | ||
401 | |||
402 | key_ref_put(key_ref); | ||
403 | error: | ||
404 | kleave(" = %ld", ret); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | /* | ||
378 | * Clear the specified keyring, creating an empty process keyring if one of the | 409 | * Clear the specified keyring, creating an empty process keyring if one of the |
379 | * special keyring IDs is used. | 410 | * special keyring IDs is used. |
380 | * | 411 | * |
@@ -1622,6 +1653,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1622 | (unsigned) arg4, | 1653 | (unsigned) arg4, |
1623 | (key_serial_t) arg5); | 1654 | (key_serial_t) arg5); |
1624 | 1655 | ||
1656 | case KEYCTL_INVALIDATE: | ||
1657 | return keyctl_invalidate_key((key_serial_t) arg2); | ||
1658 | |||
1625 | default: | 1659 | default: |
1626 | return -EOPNOTSUPP; | 1660 | return -EOPNOTSUPP; |
1627 | } | 1661 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index d605f75292e4..7445875f6818 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -25,6 +25,15 @@ | |||
25 | (keyring)->payload.subscriptions, \ | 25 | (keyring)->payload.subscriptions, \ |
26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
27 | 27 | ||
28 | #define rcu_deref_link_locked(klist, index, keyring) \ | ||
29 | (rcu_dereference_protected( \ | ||
30 | (klist)->keys[index], \ | ||
31 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | ||
32 | |||
33 | #define MAX_KEYRING_LINKS \ | ||
34 | min_t(size_t, USHRT_MAX - 1, \ | ||
35 | ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) | ||
36 | |||
28 | #define KEY_LINK_FIXQUOTA 1UL | 37 | #define KEY_LINK_FIXQUOTA 1UL |
29 | 38 | ||
30 | /* | 39 | /* |
@@ -138,6 +147,11 @@ static int keyring_match(const struct key *keyring, const void *description) | |||
138 | /* | 147 | /* |
139 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one | 148 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one |
140 | * and dispose of its data. | 149 | * and dispose of its data. |
150 | * | ||
151 | * The garbage collector detects the final key_put(), removes the keyring from | ||
152 | * the serial number tree and then does RCU synchronisation before coming here, | ||
153 | * so we shouldn't need to worry about code poking around here with the RCU | ||
154 | * readlock held by this time. | ||
141 | */ | 155 | */ |
142 | static void keyring_destroy(struct key *keyring) | 156 | static void keyring_destroy(struct key *keyring) |
143 | { | 157 | { |
@@ -154,11 +168,10 @@ static void keyring_destroy(struct key *keyring) | |||
154 | write_unlock(&keyring_name_lock); | 168 | write_unlock(&keyring_name_lock); |
155 | } | 169 | } |
156 | 170 | ||
157 | klist = rcu_dereference_check(keyring->payload.subscriptions, | 171 | klist = rcu_access_pointer(keyring->payload.subscriptions); |
158 | atomic_read(&keyring->usage) == 0); | ||
159 | if (klist) { | 172 | if (klist) { |
160 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 173 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
161 | key_put(klist->keys[loop]); | 174 | key_put(rcu_access_pointer(klist->keys[loop])); |
162 | kfree(klist); | 175 | kfree(klist); |
163 | } | 176 | } |
164 | } | 177 | } |
@@ -214,7 +227,8 @@ static long keyring_read(const struct key *keyring, | |||
214 | ret = -EFAULT; | 227 | ret = -EFAULT; |
215 | 228 | ||
216 | for (loop = 0; loop < klist->nkeys; loop++) { | 229 | for (loop = 0; loop < klist->nkeys; loop++) { |
217 | key = klist->keys[loop]; | 230 | key = rcu_deref_link_locked(klist, loop, |
231 | keyring); | ||
218 | 232 | ||
219 | tmp = sizeof(key_serial_t); | 233 | tmp = sizeof(key_serial_t); |
220 | if (tmp > buflen) | 234 | if (tmp > buflen) |
@@ -309,6 +323,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
309 | bool no_state_check) | 323 | bool no_state_check) |
310 | { | 324 | { |
311 | struct { | 325 | struct { |
326 | /* Need a separate keylist pointer for RCU purposes */ | ||
327 | struct key *keyring; | ||
312 | struct keyring_list *keylist; | 328 | struct keyring_list *keylist; |
313 | int kix; | 329 | int kix; |
314 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 330 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
@@ -366,13 +382,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
366 | /* otherwise, the top keyring must not be revoked, expired, or | 382 | /* otherwise, the top keyring must not be revoked, expired, or |
367 | * negatively instantiated if we are to search it */ | 383 | * negatively instantiated if we are to search it */ |
368 | key_ref = ERR_PTR(-EAGAIN); | 384 | key_ref = ERR_PTR(-EAGAIN); |
369 | if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || | 385 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
386 | (1 << KEY_FLAG_REVOKED) | | ||
387 | (1 << KEY_FLAG_NEGATIVE)) || | ||
370 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | 388 | (keyring->expiry && now.tv_sec >= keyring->expiry)) |
371 | goto error_2; | 389 | goto error_2; |
372 | 390 | ||
373 | /* start processing a new keyring */ | 391 | /* start processing a new keyring */ |
374 | descend: | 392 | descend: |
375 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 393 | kflags = keyring->flags; |
394 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | ||
395 | (1 << KEY_FLAG_REVOKED))) | ||
376 | goto not_this_keyring; | 396 | goto not_this_keyring; |
377 | 397 | ||
378 | keylist = rcu_dereference(keyring->payload.subscriptions); | 398 | keylist = rcu_dereference(keyring->payload.subscriptions); |
@@ -383,16 +403,17 @@ descend: | |||
383 | nkeys = keylist->nkeys; | 403 | nkeys = keylist->nkeys; |
384 | smp_rmb(); | 404 | smp_rmb(); |
385 | for (kix = 0; kix < nkeys; kix++) { | 405 | for (kix = 0; kix < nkeys; kix++) { |
386 | key = keylist->keys[kix]; | 406 | key = rcu_dereference(keylist->keys[kix]); |
387 | kflags = key->flags; | 407 | kflags = key->flags; |
388 | 408 | ||
389 | /* ignore keys not of this type */ | 409 | /* ignore keys not of this type */ |
390 | if (key->type != type) | 410 | if (key->type != type) |
391 | continue; | 411 | continue; |
392 | 412 | ||
393 | /* skip revoked keys and expired keys */ | 413 | /* skip invalidated, revoked and expired keys */ |
394 | if (!no_state_check) { | 414 | if (!no_state_check) { |
395 | if (kflags & (1 << KEY_FLAG_REVOKED)) | 415 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
416 | (1 << KEY_FLAG_REVOKED))) | ||
396 | continue; | 417 | continue; |
397 | 418 | ||
398 | if (key->expiry && now.tv_sec >= key->expiry) | 419 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -426,7 +447,7 @@ ascend: | |||
426 | nkeys = keylist->nkeys; | 447 | nkeys = keylist->nkeys; |
427 | smp_rmb(); | 448 | smp_rmb(); |
428 | for (; kix < nkeys; kix++) { | 449 | for (; kix < nkeys; kix++) { |
429 | key = keylist->keys[kix]; | 450 | key = rcu_dereference(keylist->keys[kix]); |
430 | if (key->type != &key_type_keyring) | 451 | if (key->type != &key_type_keyring) |
431 | continue; | 452 | continue; |
432 | 453 | ||
@@ -441,6 +462,7 @@ ascend: | |||
441 | continue; | 462 | continue; |
442 | 463 | ||
443 | /* stack the current position */ | 464 | /* stack the current position */ |
465 | stack[sp].keyring = keyring; | ||
444 | stack[sp].keylist = keylist; | 466 | stack[sp].keylist = keylist; |
445 | stack[sp].kix = kix; | 467 | stack[sp].kix = kix; |
446 | sp++; | 468 | sp++; |
@@ -456,6 +478,7 @@ not_this_keyring: | |||
456 | if (sp > 0) { | 478 | if (sp > 0) { |
457 | /* resume the processing of a keyring higher up in the tree */ | 479 | /* resume the processing of a keyring higher up in the tree */ |
458 | sp--; | 480 | sp--; |
481 | keyring = stack[sp].keyring; | ||
459 | keylist = stack[sp].keylist; | 482 | keylist = stack[sp].keylist; |
460 | kix = stack[sp].kix + 1; | 483 | kix = stack[sp].kix + 1; |
461 | goto ascend; | 484 | goto ascend; |
@@ -467,6 +490,10 @@ not_this_keyring: | |||
467 | /* we found a viable match */ | 490 | /* we found a viable match */ |
468 | found: | 491 | found: |
469 | atomic_inc(&key->usage); | 492 | atomic_inc(&key->usage); |
493 | key->last_used_at = now.tv_sec; | ||
494 | keyring->last_used_at = now.tv_sec; | ||
495 | while (sp > 0) | ||
496 | stack[--sp].keyring->last_used_at = now.tv_sec; | ||
470 | key_check(key); | 497 | key_check(key); |
471 | key_ref = make_key_ref(key, possessed); | 498 | key_ref = make_key_ref(key, possessed); |
472 | error_2: | 499 | error_2: |
@@ -531,14 +558,14 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
531 | nkeys = klist->nkeys; | 558 | nkeys = klist->nkeys; |
532 | smp_rmb(); | 559 | smp_rmb(); |
533 | for (loop = 0; loop < nkeys ; loop++) { | 560 | for (loop = 0; loop < nkeys ; loop++) { |
534 | key = klist->keys[loop]; | 561 | key = rcu_dereference(klist->keys[loop]); |
535 | |||
536 | if (key->type == ktype && | 562 | if (key->type == ktype && |
537 | (!key->type->match || | 563 | (!key->type->match || |
538 | key->type->match(key, description)) && | 564 | key->type->match(key, description)) && |
539 | key_permission(make_key_ref(key, possessed), | 565 | key_permission(make_key_ref(key, possessed), |
540 | perm) == 0 && | 566 | perm) == 0 && |
541 | !test_bit(KEY_FLAG_REVOKED, &key->flags) | 567 | !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | |
568 | (1 << KEY_FLAG_REVOKED))) | ||
542 | ) | 569 | ) |
543 | goto found; | 570 | goto found; |
544 | } | 571 | } |
@@ -549,6 +576,8 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
549 | 576 | ||
550 | found: | 577 | found: |
551 | atomic_inc(&key->usage); | 578 | atomic_inc(&key->usage); |
579 | keyring->last_used_at = key->last_used_at = | ||
580 | current_kernel_time().tv_sec; | ||
552 | rcu_read_unlock(); | 581 | rcu_read_unlock(); |
553 | return make_key_ref(key, possessed); | 582 | return make_key_ref(key, possessed); |
554 | } | 583 | } |
@@ -602,6 +631,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
602 | * (ie. it has a zero usage count) */ | 631 | * (ie. it has a zero usage count) */ |
603 | if (!atomic_inc_not_zero(&keyring->usage)) | 632 | if (!atomic_inc_not_zero(&keyring->usage)) |
604 | continue; | 633 | continue; |
634 | keyring->last_used_at = current_kernel_time().tv_sec; | ||
605 | goto out; | 635 | goto out; |
606 | } | 636 | } |
607 | } | 637 | } |
@@ -654,7 +684,7 @@ ascend: | |||
654 | nkeys = keylist->nkeys; | 684 | nkeys = keylist->nkeys; |
655 | smp_rmb(); | 685 | smp_rmb(); |
656 | for (; kix < nkeys; kix++) { | 686 | for (; kix < nkeys; kix++) { |
657 | key = keylist->keys[kix]; | 687 | key = rcu_dereference(keylist->keys[kix]); |
658 | 688 | ||
659 | if (key == A) | 689 | if (key == A) |
660 | goto cycle_detected; | 690 | goto cycle_detected; |
@@ -711,7 +741,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
711 | container_of(rcu, struct keyring_list, rcu); | 741 | container_of(rcu, struct keyring_list, rcu); |
712 | 742 | ||
713 | if (klist->delkey != USHRT_MAX) | 743 | if (klist->delkey != USHRT_MAX) |
714 | key_put(klist->keys[klist->delkey]); | 744 | key_put(rcu_access_pointer(klist->keys[klist->delkey])); |
715 | kfree(klist); | 745 | kfree(klist); |
716 | } | 746 | } |
717 | 747 | ||
@@ -725,8 +755,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
725 | struct keyring_list *klist, *nklist; | 755 | struct keyring_list *klist, *nklist; |
726 | unsigned long prealloc; | 756 | unsigned long prealloc; |
727 | unsigned max; | 757 | unsigned max; |
758 | time_t lowest_lru; | ||
728 | size_t size; | 759 | size_t size; |
729 | int loop, ret; | 760 | int loop, lru, ret; |
730 | 761 | ||
731 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); | 762 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
732 | 763 | ||
@@ -747,31 +778,39 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
747 | klist = rcu_dereference_locked_keyring(keyring); | 778 | klist = rcu_dereference_locked_keyring(keyring); |
748 | 779 | ||
749 | /* see if there's a matching key we can displace */ | 780 | /* see if there's a matching key we can displace */ |
781 | lru = -1; | ||
750 | if (klist && klist->nkeys > 0) { | 782 | if (klist && klist->nkeys > 0) { |
783 | lowest_lru = TIME_T_MAX; | ||
751 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 784 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
752 | if (klist->keys[loop]->type == type && | 785 | struct key *key = rcu_deref_link_locked(klist, loop, |
753 | strcmp(klist->keys[loop]->description, | 786 | keyring); |
754 | description) == 0 | 787 | if (key->type == type && |
755 | ) { | 788 | strcmp(key->description, description) == 0) { |
756 | /* found a match - we'll replace this one with | 789 | /* Found a match - we'll replace the link with |
757 | * the new key */ | 790 | * one to the new key. We record the slot |
758 | size = sizeof(struct key *) * klist->maxkeys; | 791 | * position. |
759 | size += sizeof(*klist); | 792 | */ |
760 | BUG_ON(size > PAGE_SIZE); | 793 | klist->delkey = loop; |
761 | 794 | prealloc = 0; | |
762 | ret = -ENOMEM; | ||
763 | nklist = kmemdup(klist, size, GFP_KERNEL); | ||
764 | if (!nklist) | ||
765 | goto error_sem; | ||
766 | |||
767 | /* note replacement slot */ | ||
768 | klist->delkey = nklist->delkey = loop; | ||
769 | prealloc = (unsigned long)nklist; | ||
770 | goto done; | 795 | goto done; |
771 | } | 796 | } |
797 | if (key->last_used_at < lowest_lru) { | ||
798 | lowest_lru = key->last_used_at; | ||
799 | lru = loop; | ||
800 | } | ||
772 | } | 801 | } |
773 | } | 802 | } |
774 | 803 | ||
804 | /* If the keyring is full then do an LRU discard */ | ||
805 | if (klist && | ||
806 | klist->nkeys == klist->maxkeys && | ||
807 | klist->maxkeys >= MAX_KEYRING_LINKS) { | ||
808 | kdebug("LRU discard %d\n", lru); | ||
809 | klist->delkey = lru; | ||
810 | prealloc = 0; | ||
811 | goto done; | ||
812 | } | ||
813 | |||
775 | /* check that we aren't going to overrun the user's quota */ | 814 | /* check that we aren't going to overrun the user's quota */ |
776 | ret = key_payload_reserve(keyring, | 815 | ret = key_payload_reserve(keyring, |
777 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 816 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
@@ -780,20 +819,19 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
780 | 819 | ||
781 | if (klist && klist->nkeys < klist->maxkeys) { | 820 | if (klist && klist->nkeys < klist->maxkeys) { |
782 | /* there's sufficient slack space to append directly */ | 821 | /* there's sufficient slack space to append directly */ |
783 | nklist = NULL; | 822 | klist->delkey = klist->nkeys; |
784 | prealloc = KEY_LINK_FIXQUOTA; | 823 | prealloc = KEY_LINK_FIXQUOTA; |
785 | } else { | 824 | } else { |
786 | /* grow the key list */ | 825 | /* grow the key list */ |
787 | max = 4; | 826 | max = 4; |
788 | if (klist) | 827 | if (klist) { |
789 | max += klist->maxkeys; | 828 | max += klist->maxkeys; |
829 | if (max > MAX_KEYRING_LINKS) | ||
830 | max = MAX_KEYRING_LINKS; | ||
831 | BUG_ON(max <= klist->maxkeys); | ||
832 | } | ||
790 | 833 | ||
791 | ret = -ENFILE; | ||
792 | if (max > USHRT_MAX - 1) | ||
793 | goto error_quota; | ||
794 | size = sizeof(*klist) + sizeof(struct key *) * max; | 834 | size = sizeof(*klist) + sizeof(struct key *) * max; |
795 | if (size > PAGE_SIZE) | ||
796 | goto error_quota; | ||
797 | 835 | ||
798 | ret = -ENOMEM; | 836 | ret = -ENOMEM; |
799 | nklist = kmalloc(size, GFP_KERNEL); | 837 | nklist = kmalloc(size, GFP_KERNEL); |
@@ -813,10 +851,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
813 | } | 851 | } |
814 | 852 | ||
815 | /* add the key into the new space */ | 853 | /* add the key into the new space */ |
816 | nklist->keys[nklist->delkey] = NULL; | 854 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); |
855 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
817 | } | 856 | } |
818 | 857 | ||
819 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
820 | done: | 858 | done: |
821 | *_prealloc = prealloc; | 859 | *_prealloc = prealloc; |
822 | kleave(" = 0"); | 860 | kleave(" = 0"); |
@@ -862,6 +900,7 @@ void __key_link(struct key *keyring, struct key *key, | |||
862 | unsigned long *_prealloc) | 900 | unsigned long *_prealloc) |
863 | { | 901 | { |
864 | struct keyring_list *klist, *nklist; | 902 | struct keyring_list *klist, *nklist; |
903 | struct key *discard; | ||
865 | 904 | ||
866 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); | 905 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
867 | *_prealloc = 0; | 906 | *_prealloc = 0; |
@@ -871,14 +910,16 @@ void __key_link(struct key *keyring, struct key *key, | |||
871 | klist = rcu_dereference_locked_keyring(keyring); | 910 | klist = rcu_dereference_locked_keyring(keyring); |
872 | 911 | ||
873 | atomic_inc(&key->usage); | 912 | atomic_inc(&key->usage); |
913 | keyring->last_used_at = key->last_used_at = | ||
914 | current_kernel_time().tv_sec; | ||
874 | 915 | ||
875 | /* there's a matching key we can displace or an empty slot in a newly | 916 | /* there's a matching key we can displace or an empty slot in a newly |
876 | * allocated list we can fill */ | 917 | * allocated list we can fill */ |
877 | if (nklist) { | 918 | if (nklist) { |
878 | kdebug("replace %hu/%hu/%hu", | 919 | kdebug("reissue %hu/%hu/%hu", |
879 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | 920 | nklist->delkey, nklist->nkeys, nklist->maxkeys); |
880 | 921 | ||
881 | nklist->keys[nklist->delkey] = key; | 922 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); |
882 | 923 | ||
883 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | 924 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
884 | 925 | ||
@@ -889,9 +930,23 @@ void __key_link(struct key *keyring, struct key *key, | |||
889 | klist->delkey, klist->nkeys, klist->maxkeys); | 930 | klist->delkey, klist->nkeys, klist->maxkeys); |
890 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | 931 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
891 | } | 932 | } |
933 | } else if (klist->delkey < klist->nkeys) { | ||
934 | kdebug("replace %hu/%hu/%hu", | ||
935 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
936 | |||
937 | discard = rcu_dereference_protected( | ||
938 | klist->keys[klist->delkey], | ||
939 | rwsem_is_locked(&keyring->sem)); | ||
940 | rcu_assign_pointer(klist->keys[klist->delkey], key); | ||
941 | /* The garbage collector will take care of RCU | ||
942 | * synchronisation */ | ||
943 | key_put(discard); | ||
892 | } else { | 944 | } else { |
893 | /* there's sufficient slack space to append directly */ | 945 | /* there's sufficient slack space to append directly */ |
894 | klist->keys[klist->nkeys] = key; | 946 | kdebug("append %hu/%hu/%hu", |
947 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
948 | |||
949 | RCU_INIT_POINTER(klist->keys[klist->delkey], key); | ||
895 | smp_wmb(); | 950 | smp_wmb(); |
896 | klist->nkeys++; | 951 | klist->nkeys++; |
897 | } | 952 | } |
@@ -998,7 +1053,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
998 | if (klist) { | 1053 | if (klist) { |
999 | /* search the keyring for the key */ | 1054 | /* search the keyring for the key */ |
1000 | for (loop = 0; loop < klist->nkeys; loop++) | 1055 | for (loop = 0; loop < klist->nkeys; loop++) |
1001 | if (klist->keys[loop] == key) | 1056 | if (rcu_access_pointer(klist->keys[loop]) == key) |
1002 | goto key_is_present; | 1057 | goto key_is_present; |
1003 | } | 1058 | } |
1004 | 1059 | ||
@@ -1061,7 +1116,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | |||
1061 | klist = container_of(rcu, struct keyring_list, rcu); | 1116 | klist = container_of(rcu, struct keyring_list, rcu); |
1062 | 1117 | ||
1063 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1118 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1064 | key_put(klist->keys[loop]); | 1119 | key_put(rcu_access_pointer(klist->keys[loop])); |
1065 | 1120 | ||
1066 | kfree(klist); | 1121 | kfree(klist); |
1067 | } | 1122 | } |
@@ -1128,15 +1183,6 @@ static void keyring_revoke(struct key *keyring) | |||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | /* | 1185 | /* |
1131 | * Determine whether a key is dead. | ||
1132 | */ | ||
1133 | static bool key_is_dead(struct key *key, time_t limit) | ||
1134 | { | ||
1135 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
1136 | (key->expiry > 0 && key->expiry <= limit); | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Collect garbage from the contents of a keyring, replacing the old list with | 1186 | * Collect garbage from the contents of a keyring, replacing the old list with |
1141 | * a new one with the pointers all shuffled down. | 1187 | * a new one with the pointers all shuffled down. |
1142 | * | 1188 | * |
@@ -1161,7 +1207,8 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1161 | /* work out how many subscriptions we're keeping */ | 1207 | /* work out how many subscriptions we're keeping */ |
1162 | keep = 0; | 1208 | keep = 0; |
1163 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1209 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1164 | if (!key_is_dead(klist->keys[loop], limit)) | 1210 | if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), |
1211 | limit)) | ||
1165 | keep++; | 1212 | keep++; |
1166 | 1213 | ||
1167 | if (keep == klist->nkeys) | 1214 | if (keep == klist->nkeys) |
@@ -1182,11 +1229,11 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1182 | */ | 1229 | */ |
1183 | keep = 0; | 1230 | keep = 0; |
1184 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 1231 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
1185 | key = klist->keys[loop]; | 1232 | key = rcu_deref_link_locked(klist, loop, keyring); |
1186 | if (!key_is_dead(key, limit)) { | 1233 | if (!key_is_dead(key, limit)) { |
1187 | if (keep >= max) | 1234 | if (keep >= max) |
1188 | goto discard_new; | 1235 | goto discard_new; |
1189 | new->keys[keep++] = key_get(key); | 1236 | RCU_INIT_POINTER(new->keys[keep++], key_get(key)); |
1190 | } | 1237 | } |
1191 | } | 1238 | } |
1192 | new->nkeys = keep; | 1239 | new->nkeys = keep; |
diff --git a/security/keys/permission.c b/security/keys/permission.c index c35b5229e3cd..57d96363d7f1 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -87,32 +87,29 @@ EXPORT_SYMBOL(key_task_permission); | |||
87 | * key_validate - Validate a key. | 87 | * key_validate - Validate a key. |
88 | * @key: The key to be validated. | 88 | * @key: The key to be validated. |
89 | * | 89 | * |
90 | * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if | 90 | * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the |
91 | * the key's type has been removed or if the key has been revoked or | 91 | * key is invalidated, -EKEYREVOKED if the key's type has been removed or if |
92 | * -EKEYEXPIRED if the key has expired. | 92 | * the key has been revoked or -EKEYEXPIRED if the key has expired. |
93 | */ | 93 | */ |
94 | int key_validate(struct key *key) | 94 | int key_validate(const struct key *key) |
95 | { | 95 | { |
96 | struct timespec now; | 96 | unsigned long flags = key->flags; |
97 | int ret = 0; | 97 | |
98 | 98 | if (flags & (1 << KEY_FLAG_INVALIDATED)) | |
99 | if (key) { | 99 | return -ENOKEY; |
100 | /* check it's still accessible */ | 100 | |
101 | ret = -EKEYREVOKED; | 101 | /* check it's still accessible */ |
102 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | 102 | if (flags & ((1 << KEY_FLAG_REVOKED) | |
103 | test_bit(KEY_FLAG_DEAD, &key->flags)) | 103 | (1 << KEY_FLAG_DEAD))) |
104 | goto error; | 104 | return -EKEYREVOKED; |
105 | 105 | ||
106 | /* check it hasn't expired */ | 106 | /* check it hasn't expired */ |
107 | ret = 0; | 107 | if (key->expiry) { |
108 | if (key->expiry) { | 108 | struct timespec now = current_kernel_time(); |
109 | now = current_kernel_time(); | 109 | if (now.tv_sec >= key->expiry) |
110 | if (now.tv_sec >= key->expiry) | 110 | return -EKEYEXPIRED; |
111 | ret = -EKEYEXPIRED; | ||
112 | } | ||
113 | } | 111 | } |
114 | 112 | ||
115 | error: | 113 | return 0; |
116 | return ret; | ||
117 | } | 114 | } |
118 | EXPORT_SYMBOL(key_validate); | 115 | EXPORT_SYMBOL(key_validate); |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 49bbc97943ad..30d1ddfd9cef 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -242,7 +242,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
242 | #define showflag(KEY, LETTER, FLAG) \ | 242 | #define showflag(KEY, LETTER, FLAG) \ |
243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | 243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') |
244 | 244 | ||
245 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", | 245 | seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", |
246 | key->serial, | 246 | key->serial, |
247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), | 247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), |
248 | showflag(key, 'R', KEY_FLAG_REVOKED), | 248 | showflag(key, 'R', KEY_FLAG_REVOKED), |
@@ -250,6 +250,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), | 250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), |
251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | 251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), | 252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
253 | showflag(key, 'i', KEY_FLAG_INVALIDATED), | ||
253 | atomic_read(&key->usage), | 254 | atomic_read(&key->usage), |
254 | xbuf, | 255 | xbuf, |
255 | key->perm, | 256 | key->perm, |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index be7ecb2018dd..e137fcd7042c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -732,6 +732,8 @@ try_again: | |||
732 | if (ret < 0) | 732 | if (ret < 0) |
733 | goto invalid_key; | 733 | goto invalid_key; |
734 | 734 | ||
735 | key->last_used_at = current_kernel_time().tv_sec; | ||
736 | |||
735 | error: | 737 | error: |
736 | put_cred(cred); | 738 | put_cred(cred); |
737 | return key_ref; | 739 | return key_ref; |