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; |
