diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/Makefile | 5 | ||||
-rw-r--r-- | security/keys/compat.c | 7 | ||||
-rw-r--r-- | security/keys/internal.h | 45 | ||||
-rw-r--r-- | security/keys/key.c | 118 | ||||
-rw-r--r-- | security/keys/keyctl.c | 199 | ||||
-rw-r--r-- | security/keys/keyring.c | 312 | ||||
-rw-r--r-- | security/keys/proc.c | 21 | ||||
-rw-r--r-- | security/keys/process_keys.c | 213 | ||||
-rw-r--r-- | security/keys/request_key.c | 221 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 180 | ||||
-rw-r--r-- | security/keys/user_defined.c | 87 |
11 files changed, 990 insertions, 418 deletions
diff --git a/security/keys/Makefile b/security/keys/Makefile index ddb495d65062..c392d750b208 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -7,8 +7,9 @@ obj-y := \ | |||
7 | keyring.o \ | 7 | keyring.o \ |
8 | keyctl.o \ | 8 | keyctl.o \ |
9 | process_keys.o \ | 9 | process_keys.o \ |
10 | user_defined.o \ | 10 | request_key.o \ |
11 | request_key.o | 11 | request_key_auth.o \ |
12 | user_defined.o | ||
12 | 13 | ||
13 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 14 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
14 | obj-$(CONFIG_PROC_FS) += proc.o | 15 | obj-$(CONFIG_PROC_FS) += proc.o |
diff --git a/security/keys/compat.c b/security/keys/compat.c index aff8b22dcb5c..3303673c636e 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* compat.c: 32-bit compatibility syscall for 64-bit systems | 1 | /* compat.c: 32-bit compatibility syscall for 64-bit systems |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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 |
@@ -24,7 +24,7 @@ | |||
24 | * - if you can, you should call sys_keyctl directly | 24 | * - if you can, you should call sys_keyctl directly |
25 | */ | 25 | */ |
26 | asmlinkage long compat_sys_keyctl(u32 option, | 26 | asmlinkage long compat_sys_keyctl(u32 option, |
27 | u32 arg2, u32 arg3, u32 arg4, u32 arg5) | 27 | u32 arg2, u32 arg3, u32 arg4, u32 arg5) |
28 | { | 28 | { |
29 | switch (option) { | 29 | switch (option) { |
30 | case KEYCTL_GET_KEYRING_ID: | 30 | case KEYCTL_GET_KEYRING_ID: |
@@ -71,6 +71,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
71 | case KEYCTL_NEGATE: | 71 | case KEYCTL_NEGATE: |
72 | return keyctl_negate_key(arg2, arg3, arg4); | 72 | return keyctl_negate_key(arg2, arg3, arg4); |
73 | 73 | ||
74 | case KEYCTL_SET_REQKEY_KEYRING: | ||
75 | return keyctl_set_reqkey_keyring(arg2); | ||
76 | |||
74 | default: | 77 | default: |
75 | return -EOPNOTSUPP; | 78 | return -EOPNOTSUPP; |
76 | } | 79 | } |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 67b2b93a7489..46c8602661c9 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* internal.h: authentication token and access key management internal defs | 1 | /* internal.h: authentication token and access key management internal defs |
2 | * | 2 | * |
3 | * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2003-5 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 |
@@ -15,6 +15,16 @@ | |||
15 | #include <linux/key.h> | 15 | #include <linux/key.h> |
16 | #include <linux/key-ui.h> | 16 | #include <linux/key-ui.h> |
17 | 17 | ||
18 | #if 0 | ||
19 | #define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a) | ||
20 | #define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a) | ||
21 | #define kdebug(FMT, a...) printk(FMT"\n" , ## a) | ||
22 | #else | ||
23 | #define kenter(FMT, a...) do {} while(0) | ||
24 | #define kleave(FMT, a...) do {} while(0) | ||
25 | #define kdebug(FMT, a...) do {} while(0) | ||
26 | #endif | ||
27 | |||
18 | extern struct key_type key_type_dead; | 28 | extern struct key_type key_type_dead; |
19 | extern struct key_type key_type_user; | 29 | extern struct key_type key_type_user; |
20 | 30 | ||
@@ -66,20 +76,46 @@ extern struct key *__keyring_search_one(struct key *keyring, | |||
66 | const char *description, | 76 | const char *description, |
67 | key_perm_t perm); | 77 | key_perm_t perm); |
68 | 78 | ||
79 | extern struct key *keyring_search_instkey(struct key *keyring, | ||
80 | key_serial_t target_id); | ||
81 | |||
69 | typedef int (*key_match_func_t)(const struct key *, const void *); | 82 | typedef int (*key_match_func_t)(const struct key *, const void *); |
70 | 83 | ||
71 | extern struct key *keyring_search_aux(struct key *keyring, | 84 | extern struct key *keyring_search_aux(struct key *keyring, |
85 | struct task_struct *tsk, | ||
72 | struct key_type *type, | 86 | struct key_type *type, |
73 | const void *description, | 87 | const void *description, |
74 | key_match_func_t match); | 88 | key_match_func_t match); |
75 | 89 | ||
76 | extern struct key *search_process_keyrings_aux(struct key_type *type, | 90 | extern struct key *search_process_keyrings(struct key_type *type, |
77 | const void *description, | 91 | const void *description, |
78 | key_match_func_t match); | 92 | key_match_func_t match, |
93 | struct task_struct *tsk); | ||
79 | 94 | ||
80 | extern struct key *find_keyring_by_name(const char *name, key_serial_t bound); | 95 | extern struct key *find_keyring_by_name(const char *name, key_serial_t bound); |
81 | 96 | ||
82 | extern int install_thread_keyring(struct task_struct *tsk); | 97 | extern int install_thread_keyring(struct task_struct *tsk); |
98 | extern int install_process_keyring(struct task_struct *tsk); | ||
99 | |||
100 | extern struct key *request_key_and_link(struct key_type *type, | ||
101 | const char *description, | ||
102 | const char *callout_info, | ||
103 | struct key *dest_keyring); | ||
104 | |||
105 | /* | ||
106 | * request_key authorisation | ||
107 | */ | ||
108 | struct request_key_auth { | ||
109 | struct key *target_key; | ||
110 | struct task_struct *context; | ||
111 | pid_t pid; | ||
112 | }; | ||
113 | |||
114 | extern struct key_type key_type_request_key_auth; | ||
115 | extern struct key *request_key_auth_new(struct key *target, | ||
116 | struct key **_rkakey); | ||
117 | |||
118 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | ||
83 | 119 | ||
84 | /* | 120 | /* |
85 | * keyctl functions | 121 | * keyctl functions |
@@ -100,6 +136,7 @@ extern long keyctl_setperm_key(key_serial_t, key_perm_t); | |||
100 | extern long keyctl_instantiate_key(key_serial_t, const void __user *, | 136 | extern long keyctl_instantiate_key(key_serial_t, const void __user *, |
101 | size_t, key_serial_t); | 137 | size_t, key_serial_t); |
102 | extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); | 138 | extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); |
139 | extern long keyctl_set_reqkey_keyring(int); | ||
103 | 140 | ||
104 | 141 | ||
105 | /* | 142 | /* |
diff --git a/security/keys/key.c b/security/keys/key.c index 59402c843203..fb89f9844465 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* key.c: basic authentication token and access key management | 1 | /* key.c: basic authentication token and access key management |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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 |
@@ -294,7 +294,6 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
294 | } | 294 | } |
295 | 295 | ||
296 | atomic_set(&key->usage, 1); | 296 | atomic_set(&key->usage, 1); |
297 | rwlock_init(&key->lock); | ||
298 | init_rwsem(&key->sem); | 297 | init_rwsem(&key->sem); |
299 | key->type = type; | 298 | key->type = type; |
300 | key->user = user; | 299 | key->user = user; |
@@ -308,7 +307,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
308 | key->payload.data = NULL; | 307 | key->payload.data = NULL; |
309 | 308 | ||
310 | if (!not_in_quota) | 309 | if (!not_in_quota) |
311 | key->flags |= KEY_FLAG_IN_QUOTA; | 310 | key->flags |= 1 << KEY_FLAG_IN_QUOTA; |
312 | 311 | ||
313 | memset(&key->type_data, 0, sizeof(key->type_data)); | 312 | memset(&key->type_data, 0, sizeof(key->type_data)); |
314 | 313 | ||
@@ -359,7 +358,7 @@ int key_payload_reserve(struct key *key, size_t datalen) | |||
359 | key_check(key); | 358 | key_check(key); |
360 | 359 | ||
361 | /* contemplate the quota adjustment */ | 360 | /* contemplate the quota adjustment */ |
362 | if (delta != 0 && key->flags & KEY_FLAG_IN_QUOTA) { | 361 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
363 | spin_lock(&key->user->lock); | 362 | spin_lock(&key->user->lock); |
364 | 363 | ||
365 | if (delta > 0 && | 364 | if (delta > 0 && |
@@ -392,7 +391,8 @@ EXPORT_SYMBOL(key_payload_reserve); | |||
392 | static int __key_instantiate_and_link(struct key *key, | 391 | static int __key_instantiate_and_link(struct key *key, |
393 | const void *data, | 392 | const void *data, |
394 | size_t datalen, | 393 | size_t datalen, |
395 | struct key *keyring) | 394 | struct key *keyring, |
395 | struct key *instkey) | ||
396 | { | 396 | { |
397 | int ret, awaken; | 397 | int ret, awaken; |
398 | 398 | ||
@@ -405,27 +405,25 @@ static int __key_instantiate_and_link(struct key *key, | |||
405 | down_write(&key_construction_sem); | 405 | down_write(&key_construction_sem); |
406 | 406 | ||
407 | /* can't instantiate twice */ | 407 | /* can't instantiate twice */ |
408 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 408 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
409 | /* instantiate the key */ | 409 | /* instantiate the key */ |
410 | ret = key->type->instantiate(key, data, datalen); | 410 | ret = key->type->instantiate(key, data, datalen); |
411 | 411 | ||
412 | if (ret == 0) { | 412 | if (ret == 0) { |
413 | /* mark the key as being instantiated */ | 413 | /* mark the key as being instantiated */ |
414 | write_lock(&key->lock); | ||
415 | |||
416 | atomic_inc(&key->user->nikeys); | 414 | atomic_inc(&key->user->nikeys); |
417 | key->flags |= KEY_FLAG_INSTANTIATED; | 415 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
418 | 416 | ||
419 | if (key->flags & KEY_FLAG_USER_CONSTRUCT) { | 417 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
420 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
421 | awaken = 1; | 418 | awaken = 1; |
422 | } | ||
423 | |||
424 | write_unlock(&key->lock); | ||
425 | 419 | ||
426 | /* and link it into the destination keyring */ | 420 | /* and link it into the destination keyring */ |
427 | if (keyring) | 421 | if (keyring) |
428 | ret = __key_link(keyring, key); | 422 | ret = __key_link(keyring, key); |
423 | |||
424 | /* disable the authorisation key */ | ||
425 | if (instkey) | ||
426 | key_revoke(instkey); | ||
429 | } | 427 | } |
430 | } | 428 | } |
431 | 429 | ||
@@ -446,19 +444,21 @@ static int __key_instantiate_and_link(struct key *key, | |||
446 | int key_instantiate_and_link(struct key *key, | 444 | int key_instantiate_and_link(struct key *key, |
447 | const void *data, | 445 | const void *data, |
448 | size_t datalen, | 446 | size_t datalen, |
449 | struct key *keyring) | 447 | struct key *keyring, |
448 | struct key *instkey) | ||
450 | { | 449 | { |
451 | int ret; | 450 | int ret; |
452 | 451 | ||
453 | if (keyring) | 452 | if (keyring) |
454 | down_write(&keyring->sem); | 453 | down_write(&keyring->sem); |
455 | 454 | ||
456 | ret = __key_instantiate_and_link(key, data, datalen, keyring); | 455 | ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey); |
457 | 456 | ||
458 | if (keyring) | 457 | if (keyring) |
459 | up_write(&keyring->sem); | 458 | up_write(&keyring->sem); |
460 | 459 | ||
461 | return ret; | 460 | return ret; |
461 | |||
462 | } /* end key_instantiate_and_link() */ | 462 | } /* end key_instantiate_and_link() */ |
463 | 463 | ||
464 | EXPORT_SYMBOL(key_instantiate_and_link); | 464 | EXPORT_SYMBOL(key_instantiate_and_link); |
@@ -469,7 +469,8 @@ EXPORT_SYMBOL(key_instantiate_and_link); | |||
469 | */ | 469 | */ |
470 | int key_negate_and_link(struct key *key, | 470 | int key_negate_and_link(struct key *key, |
471 | unsigned timeout, | 471 | unsigned timeout, |
472 | struct key *keyring) | 472 | struct key *keyring, |
473 | struct key *instkey) | ||
473 | { | 474 | { |
474 | struct timespec now; | 475 | struct timespec now; |
475 | int ret, awaken; | 476 | int ret, awaken; |
@@ -486,26 +487,26 @@ int key_negate_and_link(struct key *key, | |||
486 | down_write(&key_construction_sem); | 487 | down_write(&key_construction_sem); |
487 | 488 | ||
488 | /* can't instantiate twice */ | 489 | /* can't instantiate twice */ |
489 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 490 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
490 | /* mark the key as being negatively instantiated */ | 491 | /* mark the key as being negatively instantiated */ |
491 | write_lock(&key->lock); | ||
492 | |||
493 | atomic_inc(&key->user->nikeys); | 492 | atomic_inc(&key->user->nikeys); |
494 | key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; | 493 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
494 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | ||
495 | now = current_kernel_time(); | 495 | now = current_kernel_time(); |
496 | key->expiry = now.tv_sec + timeout; | 496 | key->expiry = now.tv_sec + timeout; |
497 | 497 | ||
498 | if (key->flags & KEY_FLAG_USER_CONSTRUCT) { | 498 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
499 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
500 | awaken = 1; | 499 | awaken = 1; |
501 | } | ||
502 | 500 | ||
503 | write_unlock(&key->lock); | ||
504 | ret = 0; | 501 | ret = 0; |
505 | 502 | ||
506 | /* and link it into the destination keyring */ | 503 | /* and link it into the destination keyring */ |
507 | if (keyring) | 504 | if (keyring) |
508 | ret = __key_link(keyring, key); | 505 | ret = __key_link(keyring, key); |
506 | |||
507 | /* disable the authorisation key */ | ||
508 | if (instkey) | ||
509 | key_revoke(instkey); | ||
509 | } | 510 | } |
510 | 511 | ||
511 | up_write(&key_construction_sem); | 512 | up_write(&key_construction_sem); |
@@ -553,8 +554,10 @@ static void key_cleanup(void *data) | |||
553 | rb_erase(&key->serial_node, &key_serial_tree); | 554 | rb_erase(&key->serial_node, &key_serial_tree); |
554 | spin_unlock(&key_serial_lock); | 555 | spin_unlock(&key_serial_lock); |
555 | 556 | ||
557 | key_check(key); | ||
558 | |||
556 | /* deal with the user's key tracking and quota */ | 559 | /* deal with the user's key tracking and quota */ |
557 | if (key->flags & KEY_FLAG_IN_QUOTA) { | 560 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
558 | spin_lock(&key->user->lock); | 561 | spin_lock(&key->user->lock); |
559 | key->user->qnkeys--; | 562 | key->user->qnkeys--; |
560 | key->user->qnbytes -= key->quotalen; | 563 | key->user->qnbytes -= key->quotalen; |
@@ -562,7 +565,7 @@ static void key_cleanup(void *data) | |||
562 | } | 565 | } |
563 | 566 | ||
564 | atomic_dec(&key->user->nkeys); | 567 | atomic_dec(&key->user->nkeys); |
565 | if (key->flags & KEY_FLAG_INSTANTIATED) | 568 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
566 | atomic_dec(&key->user->nikeys); | 569 | atomic_dec(&key->user->nikeys); |
567 | 570 | ||
568 | key_user_put(key->user); | 571 | key_user_put(key->user); |
@@ -631,9 +634,9 @@ struct key *key_lookup(key_serial_t id) | |||
631 | goto error; | 634 | goto error; |
632 | 635 | ||
633 | found: | 636 | found: |
634 | /* pretent doesn't exist if it's dead */ | 637 | /* pretend it doesn't exist if it's dead */ |
635 | if (atomic_read(&key->usage) == 0 || | 638 | if (atomic_read(&key->usage) == 0 || |
636 | (key->flags & KEY_FLAG_DEAD) || | 639 | test_bit(KEY_FLAG_DEAD, &key->flags) || |
637 | key->type == &key_type_dead) | 640 | key->type == &key_type_dead) |
638 | goto not_found; | 641 | goto not_found; |
639 | 642 | ||
@@ -708,12 +711,9 @@ static inline struct key *__key_update(struct key *key, const void *payload, | |||
708 | 711 | ||
709 | ret = key->type->update(key, payload, plen); | 712 | ret = key->type->update(key, payload, plen); |
710 | 713 | ||
711 | if (ret == 0) { | 714 | if (ret == 0) |
712 | /* updating a negative key instantiates it */ | 715 | /* updating a negative key instantiates it */ |
713 | write_lock(&key->lock); | 716 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
714 | key->flags &= ~KEY_FLAG_NEGATIVE; | ||
715 | write_unlock(&key->lock); | ||
716 | } | ||
717 | 717 | ||
718 | up_write(&key->sem); | 718 | up_write(&key->sem); |
719 | 719 | ||
@@ -793,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring, | |||
793 | } | 793 | } |
794 | 794 | ||
795 | /* instantiate it and link it into the target keyring */ | 795 | /* instantiate it and link it into the target keyring */ |
796 | ret = __key_instantiate_and_link(key, payload, plen, keyring); | 796 | ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL); |
797 | if (ret < 0) { | 797 | if (ret < 0) { |
798 | key_put(key); | 798 | key_put(key); |
799 | key = ERR_PTR(ret); | 799 | key = ERR_PTR(ret); |
@@ -841,12 +841,9 @@ int key_update(struct key *key, const void *payload, size_t plen) | |||
841 | down_write(&key->sem); | 841 | down_write(&key->sem); |
842 | ret = key->type->update(key, payload, plen); | 842 | ret = key->type->update(key, payload, plen); |
843 | 843 | ||
844 | if (ret == 0) { | 844 | if (ret == 0) |
845 | /* updating a negative key instantiates it */ | 845 | /* updating a negative key instantiates it */ |
846 | write_lock(&key->lock); | 846 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
847 | key->flags &= ~KEY_FLAG_NEGATIVE; | ||
848 | write_unlock(&key->lock); | ||
849 | } | ||
850 | 847 | ||
851 | up_write(&key->sem); | 848 | up_write(&key->sem); |
852 | } | 849 | } |
@@ -892,10 +889,7 @@ struct key *key_duplicate(struct key *source, const char *desc) | |||
892 | goto error2; | 889 | goto error2; |
893 | 890 | ||
894 | atomic_inc(&key->user->nikeys); | 891 | atomic_inc(&key->user->nikeys); |
895 | 892 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | |
896 | write_lock(&key->lock); | ||
897 | key->flags |= KEY_FLAG_INSTANTIATED; | ||
898 | write_unlock(&key->lock); | ||
899 | 893 | ||
900 | error_k: | 894 | error_k: |
901 | up_read(&key_types_sem); | 895 | up_read(&key_types_sem); |
@@ -922,9 +916,7 @@ void key_revoke(struct key *key) | |||
922 | /* make sure no one's trying to change or use the key when we mark | 916 | /* make sure no one's trying to change or use the key when we mark |
923 | * it */ | 917 | * it */ |
924 | down_write(&key->sem); | 918 | down_write(&key->sem); |
925 | write_lock(&key->lock); | 919 | set_bit(KEY_FLAG_REVOKED, &key->flags); |
926 | key->flags |= KEY_FLAG_REVOKED; | ||
927 | write_unlock(&key->lock); | ||
928 | up_write(&key->sem); | 920 | up_write(&key->sem); |
929 | 921 | ||
930 | } /* end key_revoke() */ | 922 | } /* end key_revoke() */ |
@@ -975,24 +967,33 @@ void unregister_key_type(struct key_type *ktype) | |||
975 | /* withdraw the key type */ | 967 | /* withdraw the key type */ |
976 | list_del_init(&ktype->link); | 968 | list_del_init(&ktype->link); |
977 | 969 | ||
978 | /* need to withdraw all keys of this type */ | 970 | /* mark all the keys of this type dead */ |
979 | spin_lock(&key_serial_lock); | 971 | spin_lock(&key_serial_lock); |
980 | 972 | ||
981 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | 973 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { |
982 | key = rb_entry(_n, struct key, serial_node); | 974 | key = rb_entry(_n, struct key, serial_node); |
983 | 975 | ||
984 | if (key->type != ktype) | 976 | if (key->type == ktype) |
985 | continue; | 977 | key->type = &key_type_dead; |
978 | } | ||
979 | |||
980 | spin_unlock(&key_serial_lock); | ||
981 | |||
982 | /* make sure everyone revalidates their keys */ | ||
983 | synchronize_rcu(); | ||
986 | 984 | ||
987 | write_lock(&key->lock); | 985 | /* we should now be able to destroy the payloads of all the keys of |
988 | key->type = &key_type_dead; | 986 | * this type with impunity */ |
989 | write_unlock(&key->lock); | 987 | spin_lock(&key_serial_lock); |
988 | |||
989 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | ||
990 | key = rb_entry(_n, struct key, serial_node); | ||
990 | 991 | ||
991 | /* there shouldn't be anyone looking at the description or | 992 | if (key->type == ktype) { |
992 | * payload now */ | 993 | if (ktype->destroy) |
993 | if (ktype->destroy) | 994 | ktype->destroy(key); |
994 | ktype->destroy(key); | 995 | memset(&key->payload, 0xbd, sizeof(key->payload)); |
995 | memset(&key->payload, 0xbd, sizeof(key->payload)); | 996 | } |
996 | } | 997 | } |
997 | 998 | ||
998 | spin_unlock(&key_serial_lock); | 999 | spin_unlock(&key_serial_lock); |
@@ -1037,4 +1038,5 @@ void __init key_init(void) | |||
1037 | 1038 | ||
1038 | /* link the two root keyrings together */ | 1039 | /* link the two root keyrings together */ |
1039 | key_link(&root_session_keyring, &root_user_keyring); | 1040 | key_link(&root_session_keyring, &root_user_keyring); |
1041 | |||
1040 | } /* end key_init() */ | 1042 | } /* end key_init() */ |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index dc0011b3fac9..fea262860ea0 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* keyctl.c: userspace keyctl operations | 1 | /* keyctl.c: userspace keyctl operations |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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 |
@@ -49,6 +49,13 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
49 | goto error; | 49 | goto error; |
50 | type[31] = '\0'; | 50 | type[31] = '\0'; |
51 | 51 | ||
52 | if (!type[0]) | ||
53 | goto error; | ||
54 | |||
55 | ret = -EPERM; | ||
56 | if (type[0] == '.') | ||
57 | goto error; | ||
58 | |||
52 | ret = -EFAULT; | 59 | ret = -EFAULT; |
53 | dlen = strnlen_user(_description, PAGE_SIZE - 1); | 60 | dlen = strnlen_user(_description, PAGE_SIZE - 1); |
54 | if (dlen <= 0) | 61 | if (dlen <= 0) |
@@ -82,7 +89,7 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
82 | } | 89 | } |
83 | 90 | ||
84 | /* find the target keyring (which must be writable) */ | 91 | /* find the target keyring (which must be writable) */ |
85 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 92 | keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
86 | if (IS_ERR(keyring)) { | 93 | if (IS_ERR(keyring)) { |
87 | ret = PTR_ERR(keyring); | 94 | ret = PTR_ERR(keyring); |
88 | goto error3; | 95 | goto error3; |
@@ -181,7 +188,7 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
181 | /* get the destination keyring if specified */ | 188 | /* get the destination keyring if specified */ |
182 | dest = NULL; | 189 | dest = NULL; |
183 | if (destringid) { | 190 | if (destringid) { |
184 | dest = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 191 | dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); |
185 | if (IS_ERR(dest)) { | 192 | if (IS_ERR(dest)) { |
186 | ret = PTR_ERR(dest); | 193 | ret = PTR_ERR(dest); |
187 | goto error3; | 194 | goto error3; |
@@ -196,23 +203,15 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
196 | } | 203 | } |
197 | 204 | ||
198 | /* do the search */ | 205 | /* do the search */ |
199 | key = request_key(ktype, description, callout_info); | 206 | key = request_key_and_link(ktype, description, callout_info, dest); |
200 | if (IS_ERR(key)) { | 207 | if (IS_ERR(key)) { |
201 | ret = PTR_ERR(key); | 208 | ret = PTR_ERR(key); |
202 | goto error5; | 209 | goto error5; |
203 | } | 210 | } |
204 | 211 | ||
205 | /* link the resulting key to the destination keyring */ | ||
206 | if (dest) { | ||
207 | ret = key_link(dest, key); | ||
208 | if (ret < 0) | ||
209 | goto error6; | ||
210 | } | ||
211 | |||
212 | ret = key->serial; | 212 | ret = key->serial; |
213 | 213 | ||
214 | error6: | 214 | key_put(key); |
215 | key_put(key); | ||
216 | error5: | 215 | error5: |
217 | key_type_put(ktype); | 216 | key_type_put(ktype); |
218 | error4: | 217 | error4: |
@@ -237,7 +236,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) | |||
237 | struct key *key; | 236 | struct key *key; |
238 | long ret; | 237 | long ret; |
239 | 238 | ||
240 | key = lookup_user_key(id, create, 0, KEY_SEARCH); | 239 | key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH); |
241 | if (IS_ERR(key)) { | 240 | if (IS_ERR(key)) { |
242 | ret = PTR_ERR(key); | 241 | ret = PTR_ERR(key); |
243 | goto error; | 242 | goto error; |
@@ -324,7 +323,7 @@ long keyctl_update_key(key_serial_t id, | |||
324 | } | 323 | } |
325 | 324 | ||
326 | /* find the target key (which must be writable) */ | 325 | /* find the target key (which must be writable) */ |
327 | key = lookup_user_key(id, 0, 0, KEY_WRITE); | 326 | key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); |
328 | if (IS_ERR(key)) { | 327 | if (IS_ERR(key)) { |
329 | ret = PTR_ERR(key); | 328 | ret = PTR_ERR(key); |
330 | goto error2; | 329 | goto error2; |
@@ -352,7 +351,7 @@ long keyctl_revoke_key(key_serial_t id) | |||
352 | struct key *key; | 351 | struct key *key; |
353 | long ret; | 352 | long ret; |
354 | 353 | ||
355 | key = lookup_user_key(id, 0, 0, KEY_WRITE); | 354 | key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); |
356 | if (IS_ERR(key)) { | 355 | if (IS_ERR(key)) { |
357 | ret = PTR_ERR(key); | 356 | ret = PTR_ERR(key); |
358 | goto error; | 357 | goto error; |
@@ -378,7 +377,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
378 | struct key *keyring; | 377 | struct key *keyring; |
379 | long ret; | 378 | long ret; |
380 | 379 | ||
381 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 380 | keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
382 | if (IS_ERR(keyring)) { | 381 | if (IS_ERR(keyring)) { |
383 | ret = PTR_ERR(keyring); | 382 | ret = PTR_ERR(keyring); |
384 | goto error; | 383 | goto error; |
@@ -404,13 +403,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
404 | struct key *keyring, *key; | 403 | struct key *keyring, *key; |
405 | long ret; | 404 | long ret; |
406 | 405 | ||
407 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 406 | keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
408 | if (IS_ERR(keyring)) { | 407 | if (IS_ERR(keyring)) { |
409 | ret = PTR_ERR(keyring); | 408 | ret = PTR_ERR(keyring); |
410 | goto error; | 409 | goto error; |
411 | } | 410 | } |
412 | 411 | ||
413 | key = lookup_user_key(id, 1, 0, KEY_LINK); | 412 | key = lookup_user_key(NULL, id, 1, 0, KEY_LINK); |
414 | if (IS_ERR(key)) { | 413 | if (IS_ERR(key)) { |
415 | ret = PTR_ERR(key); | 414 | ret = PTR_ERR(key); |
416 | goto error2; | 415 | goto error2; |
@@ -438,13 +437,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
438 | struct key *keyring, *key; | 437 | struct key *keyring, *key; |
439 | long ret; | 438 | long ret; |
440 | 439 | ||
441 | keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE); | 440 | keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); |
442 | if (IS_ERR(keyring)) { | 441 | if (IS_ERR(keyring)) { |
443 | ret = PTR_ERR(keyring); | 442 | ret = PTR_ERR(keyring); |
444 | goto error; | 443 | goto error; |
445 | } | 444 | } |
446 | 445 | ||
447 | key = lookup_user_key(id, 0, 0, 0); | 446 | key = lookup_user_key(NULL, id, 0, 0, 0); |
448 | if (IS_ERR(key)) { | 447 | if (IS_ERR(key)) { |
449 | ret = PTR_ERR(key); | 448 | ret = PTR_ERR(key); |
450 | goto error2; | 449 | goto error2; |
@@ -475,16 +474,29 @@ long keyctl_describe_key(key_serial_t keyid, | |||
475 | char __user *buffer, | 474 | char __user *buffer, |
476 | size_t buflen) | 475 | size_t buflen) |
477 | { | 476 | { |
478 | struct key *key; | 477 | struct key *key, *instkey; |
479 | char *tmpbuf; | 478 | char *tmpbuf; |
480 | long ret; | 479 | long ret; |
481 | 480 | ||
482 | key = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 481 | key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); |
483 | if (IS_ERR(key)) { | 482 | if (IS_ERR(key)) { |
483 | /* viewing a key under construction is permitted if we have the | ||
484 | * authorisation token handy */ | ||
485 | if (PTR_ERR(key) == -EACCES) { | ||
486 | instkey = key_get_instantiation_authkey(keyid); | ||
487 | if (!IS_ERR(instkey)) { | ||
488 | key_put(instkey); | ||
489 | key = lookup_user_key(NULL, keyid, 0, 1, 0); | ||
490 | if (!IS_ERR(key)) | ||
491 | goto okay; | ||
492 | } | ||
493 | } | ||
494 | |||
484 | ret = PTR_ERR(key); | 495 | ret = PTR_ERR(key); |
485 | goto error; | 496 | goto error; |
486 | } | 497 | } |
487 | 498 | ||
499 | okay: | ||
488 | /* calculate how much description we're going to return */ | 500 | /* calculate how much description we're going to return */ |
489 | ret = -ENOMEM; | 501 | ret = -ENOMEM; |
490 | tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 502 | tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
@@ -568,7 +580,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
568 | goto error2; | 580 | goto error2; |
569 | 581 | ||
570 | /* get the keyring at which to begin the search */ | 582 | /* get the keyring at which to begin the search */ |
571 | keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH); | 583 | keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); |
572 | if (IS_ERR(keyring)) { | 584 | if (IS_ERR(keyring)) { |
573 | ret = PTR_ERR(keyring); | 585 | ret = PTR_ERR(keyring); |
574 | goto error2; | 586 | goto error2; |
@@ -577,7 +589,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
577 | /* get the destination keyring if specified */ | 589 | /* get the destination keyring if specified */ |
578 | dest = NULL; | 590 | dest = NULL; |
579 | if (destringid) { | 591 | if (destringid) { |
580 | dest = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 592 | dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); |
581 | if (IS_ERR(dest)) { | 593 | if (IS_ERR(dest)) { |
582 | ret = PTR_ERR(dest); | 594 | ret = PTR_ERR(dest); |
583 | goto error3; | 595 | goto error3; |
@@ -656,24 +668,23 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
656 | long ret; | 668 | long ret; |
657 | 669 | ||
658 | /* find the key first */ | 670 | /* find the key first */ |
659 | key = lookup_user_key(keyid, 0, 0, 0); | 671 | key = lookup_user_key(NULL, keyid, 0, 0, 0); |
660 | if (!IS_ERR(key)) { | 672 | if (!IS_ERR(key)) { |
661 | /* see if we can read it directly */ | 673 | /* see if we can read it directly */ |
662 | if (key_permission(key, KEY_READ)) | 674 | if (key_permission(key, KEY_READ)) |
663 | goto can_read_key; | 675 | goto can_read_key; |
664 | 676 | ||
665 | /* can't; see if it's searchable from this process's | 677 | /* we can't; see if it's searchable from this process's |
666 | * keyrings */ | 678 | * keyrings |
667 | ret = -ENOKEY; | 679 | * - we automatically take account of the fact that it may be |
668 | if (key_permission(key, KEY_SEARCH)) { | 680 | * dangling off an instantiation key |
669 | /* okay - we do have search permission on the key | 681 | */ |
670 | * itself, but do we have the key? */ | 682 | skey = search_process_keyrings(key->type, key, |
671 | skey = search_process_keyrings_aux(key->type, key, | 683 | keyctl_read_key_same, current); |
672 | keyctl_read_key_same); | 684 | if (!IS_ERR(skey)) |
673 | if (!IS_ERR(skey)) | 685 | goto can_read_key2; |
674 | goto can_read_key2; | 686 | |
675 | } | 687 | ret = PTR_ERR(skey); |
676 | |||
677 | goto error2; | 688 | goto error2; |
678 | } | 689 | } |
679 | 690 | ||
@@ -719,7 +730,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
719 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | 730 | if (uid == (uid_t) -1 && gid == (gid_t) -1) |
720 | goto error; | 731 | goto error; |
721 | 732 | ||
722 | key = lookup_user_key(id, 1, 1, 0); | 733 | key = lookup_user_key(NULL, id, 1, 1, 0); |
723 | if (IS_ERR(key)) { | 734 | if (IS_ERR(key)) { |
724 | ret = PTR_ERR(key); | 735 | ret = PTR_ERR(key); |
725 | goto error; | 736 | goto error; |
@@ -728,7 +739,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
728 | /* make the changes with the locks held to prevent chown/chown races */ | 739 | /* make the changes with the locks held to prevent chown/chown races */ |
729 | ret = -EACCES; | 740 | ret = -EACCES; |
730 | down_write(&key->sem); | 741 | down_write(&key->sem); |
731 | write_lock(&key->lock); | ||
732 | 742 | ||
733 | if (!capable(CAP_SYS_ADMIN)) { | 743 | if (!capable(CAP_SYS_ADMIN)) { |
734 | /* only the sysadmin can chown a key to some other UID */ | 744 | /* only the sysadmin can chown a key to some other UID */ |
@@ -755,7 +765,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
755 | ret = 0; | 765 | ret = 0; |
756 | 766 | ||
757 | no_access: | 767 | no_access: |
758 | write_unlock(&key->lock); | ||
759 | up_write(&key->sem); | 768 | up_write(&key->sem); |
760 | key_put(key); | 769 | key_put(key); |
761 | error: | 770 | error: |
@@ -778,32 +787,25 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
778 | if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) | 787 | if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) |
779 | goto error; | 788 | goto error; |
780 | 789 | ||
781 | key = lookup_user_key(id, 1, 1, 0); | 790 | key = lookup_user_key(NULL, id, 1, 1, 0); |
782 | if (IS_ERR(key)) { | 791 | if (IS_ERR(key)) { |
783 | ret = PTR_ERR(key); | 792 | ret = PTR_ERR(key); |
784 | goto error; | 793 | goto error; |
785 | } | 794 | } |
786 | 795 | ||
787 | /* make the changes with the locks held to prevent chown/chmod | 796 | /* make the changes with the locks held to prevent chown/chmod races */ |
788 | * races */ | ||
789 | ret = -EACCES; | 797 | ret = -EACCES; |
790 | down_write(&key->sem); | 798 | down_write(&key->sem); |
791 | write_lock(&key->lock); | ||
792 | 799 | ||
793 | /* if we're not the sysadmin, we can only chmod a key that we | 800 | /* if we're not the sysadmin, we can only change a key that we own */ |
794 | * own */ | 801 | if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) { |
795 | if (!capable(CAP_SYS_ADMIN) && key->uid != current->fsuid) | 802 | key->perm = perm; |
796 | goto no_access; | 803 | ret = 0; |
797 | 804 | } | |
798 | /* changing the permissions mask */ | ||
799 | key->perm = perm; | ||
800 | ret = 0; | ||
801 | 805 | ||
802 | no_access: | ||
803 | write_unlock(&key->lock); | ||
804 | up_write(&key->sem); | 806 | up_write(&key->sem); |
805 | key_put(key); | 807 | key_put(key); |
806 | error: | 808 | error: |
807 | return ret; | 809 | return ret; |
808 | 810 | ||
809 | } /* end keyctl_setperm_key() */ | 811 | } /* end keyctl_setperm_key() */ |
@@ -818,7 +820,8 @@ long keyctl_instantiate_key(key_serial_t id, | |||
818 | size_t plen, | 820 | size_t plen, |
819 | key_serial_t ringid) | 821 | key_serial_t ringid) |
820 | { | 822 | { |
821 | struct key *key, *keyring; | 823 | struct request_key_auth *rka; |
824 | struct key *instkey, *keyring; | ||
822 | void *payload; | 825 | void *payload; |
823 | long ret; | 826 | long ret; |
824 | 827 | ||
@@ -840,18 +843,21 @@ long keyctl_instantiate_key(key_serial_t id, | |||
840 | goto error2; | 843 | goto error2; |
841 | } | 844 | } |
842 | 845 | ||
843 | /* find the target key (which must be writable) */ | 846 | /* find the instantiation authorisation key */ |
844 | key = lookup_user_key(id, 0, 1, KEY_WRITE); | 847 | instkey = key_get_instantiation_authkey(id); |
845 | if (IS_ERR(key)) { | 848 | if (IS_ERR(instkey)) { |
846 | ret = PTR_ERR(key); | 849 | ret = PTR_ERR(instkey); |
847 | goto error2; | 850 | goto error2; |
848 | } | 851 | } |
849 | 852 | ||
850 | /* find the destination keyring if present (which must also be | 853 | rka = instkey->payload.data; |
851 | * writable) */ | 854 | |
855 | /* find the destination keyring amongst those belonging to the | ||
856 | * requesting task */ | ||
852 | keyring = NULL; | 857 | keyring = NULL; |
853 | if (ringid) { | 858 | if (ringid) { |
854 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 859 | keyring = lookup_user_key(rka->context, ringid, 1, 0, |
860 | KEY_WRITE); | ||
855 | if (IS_ERR(keyring)) { | 861 | if (IS_ERR(keyring)) { |
856 | ret = PTR_ERR(keyring); | 862 | ret = PTR_ERR(keyring); |
857 | goto error3; | 863 | goto error3; |
@@ -859,11 +865,12 @@ long keyctl_instantiate_key(key_serial_t id, | |||
859 | } | 865 | } |
860 | 866 | ||
861 | /* instantiate the key and link it into a keyring */ | 867 | /* instantiate the key and link it into a keyring */ |
862 | ret = key_instantiate_and_link(key, payload, plen, keyring); | 868 | ret = key_instantiate_and_link(rka->target_key, payload, plen, |
869 | keyring, instkey); | ||
863 | 870 | ||
864 | key_put(keyring); | 871 | key_put(keyring); |
865 | error3: | 872 | error3: |
866 | key_put(key); | 873 | key_put(instkey); |
867 | error2: | 874 | error2: |
868 | kfree(payload); | 875 | kfree(payload); |
869 | error: | 876 | error: |
@@ -878,21 +885,24 @@ long keyctl_instantiate_key(key_serial_t id, | |||
878 | */ | 885 | */ |
879 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | 886 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) |
880 | { | 887 | { |
881 | struct key *key, *keyring; | 888 | struct request_key_auth *rka; |
889 | struct key *instkey, *keyring; | ||
882 | long ret; | 890 | long ret; |
883 | 891 | ||
884 | /* find the target key (which must be writable) */ | 892 | /* find the instantiation authorisation key */ |
885 | key = lookup_user_key(id, 0, 1, KEY_WRITE); | 893 | instkey = key_get_instantiation_authkey(id); |
886 | if (IS_ERR(key)) { | 894 | if (IS_ERR(instkey)) { |
887 | ret = PTR_ERR(key); | 895 | ret = PTR_ERR(instkey); |
888 | goto error; | 896 | goto error; |
889 | } | 897 | } |
890 | 898 | ||
899 | rka = instkey->payload.data; | ||
900 | |||
891 | /* find the destination keyring if present (which must also be | 901 | /* find the destination keyring if present (which must also be |
892 | * writable) */ | 902 | * writable) */ |
893 | keyring = NULL; | 903 | keyring = NULL; |
894 | if (ringid) { | 904 | if (ringid) { |
895 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 905 | keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
896 | if (IS_ERR(keyring)) { | 906 | if (IS_ERR(keyring)) { |
897 | ret = PTR_ERR(keyring); | 907 | ret = PTR_ERR(keyring); |
898 | goto error2; | 908 | goto error2; |
@@ -900,11 +910,11 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |||
900 | } | 910 | } |
901 | 911 | ||
902 | /* instantiate the key and link it into a keyring */ | 912 | /* instantiate the key and link it into a keyring */ |
903 | ret = key_negate_and_link(key, timeout, keyring); | 913 | ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey); |
904 | 914 | ||
905 | key_put(keyring); | 915 | key_put(keyring); |
906 | error2: | 916 | error2: |
907 | key_put(key); | 917 | key_put(instkey); |
908 | error: | 918 | error: |
909 | return ret; | 919 | return ret; |
910 | 920 | ||
@@ -912,6 +922,44 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |||
912 | 922 | ||
913 | /*****************************************************************************/ | 923 | /*****************************************************************************/ |
914 | /* | 924 | /* |
925 | * set the default keyring in which request_key() will cache keys | ||
926 | * - return the old setting | ||
927 | */ | ||
928 | long keyctl_set_reqkey_keyring(int reqkey_defl) | ||
929 | { | ||
930 | int ret; | ||
931 | |||
932 | switch (reqkey_defl) { | ||
933 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | ||
934 | ret = install_thread_keyring(current); | ||
935 | if (ret < 0) | ||
936 | return ret; | ||
937 | goto set; | ||
938 | |||
939 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | ||
940 | ret = install_process_keyring(current); | ||
941 | if (ret < 0) | ||
942 | return ret; | ||
943 | |||
944 | case KEY_REQKEY_DEFL_DEFAULT: | ||
945 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | ||
946 | case KEY_REQKEY_DEFL_USER_KEYRING: | ||
947 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | ||
948 | set: | ||
949 | current->jit_keyring = reqkey_defl; | ||
950 | |||
951 | case KEY_REQKEY_DEFL_NO_CHANGE: | ||
952 | return current->jit_keyring; | ||
953 | |||
954 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | ||
955 | default: | ||
956 | return -EINVAL; | ||
957 | } | ||
958 | |||
959 | } /* end keyctl_set_reqkey_keyring() */ | ||
960 | |||
961 | /*****************************************************************************/ | ||
962 | /* | ||
915 | * the key control system call | 963 | * the key control system call |
916 | */ | 964 | */ |
917 | asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | 965 | asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, |
@@ -980,6 +1028,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
980 | (unsigned) arg3, | 1028 | (unsigned) arg3, |
981 | (key_serial_t) arg4); | 1029 | (key_serial_t) arg4); |
982 | 1030 | ||
1031 | case KEYCTL_SET_REQKEY_KEYRING: | ||
1032 | return keyctl_set_reqkey_keyring(arg2); | ||
1033 | |||
983 | default: | 1034 | default: |
984 | return -EOPNOTSUPP; | 1035 | return -EOPNOTSUPP; |
985 | } | 1036 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e2ab4f8e7481..90a551e4da66 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* keyring.c: keyring handling | 1 | /* keyring.c: keyring handling |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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 |
@@ -132,10 +132,17 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
132 | (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key); | 132 | (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key); |
133 | 133 | ||
134 | ret = 0; | 134 | ret = 0; |
135 | sklist = source->payload.subscriptions; | ||
136 | 135 | ||
137 | if (sklist && sklist->nkeys > 0) { | 136 | /* find out how many keys are currently linked */ |
137 | rcu_read_lock(); | ||
138 | sklist = rcu_dereference(source->payload.subscriptions); | ||
139 | max = 0; | ||
140 | if (sklist) | ||
138 | max = sklist->nkeys; | 141 | max = sklist->nkeys; |
142 | rcu_read_unlock(); | ||
143 | |||
144 | /* allocate a new payload and stuff load with key links */ | ||
145 | if (max > 0) { | ||
139 | BUG_ON(max > limit); | 146 | BUG_ON(max > limit); |
140 | 147 | ||
141 | max = (max + 3) & ~3; | 148 | max = (max + 3) & ~3; |
@@ -148,6 +155,10 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
148 | if (!klist) | 155 | if (!klist) |
149 | goto error; | 156 | goto error; |
150 | 157 | ||
158 | /* set links */ | ||
159 | rcu_read_lock(); | ||
160 | sklist = rcu_dereference(source->payload.subscriptions); | ||
161 | |||
151 | klist->maxkeys = max; | 162 | klist->maxkeys = max; |
152 | klist->nkeys = sklist->nkeys; | 163 | klist->nkeys = sklist->nkeys; |
153 | memcpy(klist->keys, | 164 | memcpy(klist->keys, |
@@ -157,7 +168,9 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
157 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 168 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
158 | atomic_inc(&klist->keys[loop]->usage); | 169 | atomic_inc(&klist->keys[loop]->usage); |
159 | 170 | ||
160 | keyring->payload.subscriptions = klist; | 171 | rcu_read_unlock(); |
172 | |||
173 | rcu_assign_pointer(keyring->payload.subscriptions, klist); | ||
161 | ret = 0; | 174 | ret = 0; |
162 | } | 175 | } |
163 | 176 | ||
@@ -192,7 +205,7 @@ static void keyring_destroy(struct key *keyring) | |||
192 | write_unlock(&keyring_name_lock); | 205 | write_unlock(&keyring_name_lock); |
193 | } | 206 | } |
194 | 207 | ||
195 | klist = keyring->payload.subscriptions; | 208 | klist = rcu_dereference(keyring->payload.subscriptions); |
196 | if (klist) { | 209 | if (klist) { |
197 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 210 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
198 | key_put(klist->keys[loop]); | 211 | key_put(klist->keys[loop]); |
@@ -216,17 +229,20 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) | |||
216 | seq_puts(m, "[anon]"); | 229 | seq_puts(m, "[anon]"); |
217 | } | 230 | } |
218 | 231 | ||
219 | klist = keyring->payload.subscriptions; | 232 | rcu_read_lock(); |
233 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
220 | if (klist) | 234 | if (klist) |
221 | seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); | 235 | seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); |
222 | else | 236 | else |
223 | seq_puts(m, ": empty"); | 237 | seq_puts(m, ": empty"); |
238 | rcu_read_unlock(); | ||
224 | 239 | ||
225 | } /* end keyring_describe() */ | 240 | } /* end keyring_describe() */ |
226 | 241 | ||
227 | /*****************************************************************************/ | 242 | /*****************************************************************************/ |
228 | /* | 243 | /* |
229 | * read a list of key IDs from the keyring's contents | 244 | * read a list of key IDs from the keyring's contents |
245 | * - the keyring's semaphore is read-locked | ||
230 | */ | 246 | */ |
231 | static long keyring_read(const struct key *keyring, | 247 | static long keyring_read(const struct key *keyring, |
232 | char __user *buffer, size_t buflen) | 248 | char __user *buffer, size_t buflen) |
@@ -237,7 +253,7 @@ static long keyring_read(const struct key *keyring, | |||
237 | int loop, ret; | 253 | int loop, ret; |
238 | 254 | ||
239 | ret = 0; | 255 | ret = 0; |
240 | klist = keyring->payload.subscriptions; | 256 | klist = rcu_dereference(keyring->payload.subscriptions); |
241 | 257 | ||
242 | if (klist) { | 258 | if (klist) { |
243 | /* calculate how much data we could return */ | 259 | /* calculate how much data we could return */ |
@@ -292,7 +308,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | |||
292 | uid, gid, KEY_USR_ALL, not_in_quota); | 308 | uid, gid, KEY_USR_ALL, not_in_quota); |
293 | 309 | ||
294 | if (!IS_ERR(keyring)) { | 310 | if (!IS_ERR(keyring)) { |
295 | ret = key_instantiate_and_link(keyring, NULL, 0, dest); | 311 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); |
296 | if (ret < 0) { | 312 | if (ret < 0) { |
297 | key_put(keyring); | 313 | key_put(keyring); |
298 | keyring = ERR_PTR(ret); | 314 | keyring = ERR_PTR(ret); |
@@ -310,17 +326,18 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | |||
310 | * - we only find keys on which we have search permission | 326 | * - we only find keys on which we have search permission |
311 | * - we use the supplied match function to see if the description (or other | 327 | * - we use the supplied match function to see if the description (or other |
312 | * feature of interest) matches | 328 | * feature of interest) matches |
313 | * - we readlock the keyrings as we search down the tree | 329 | * - we rely on RCU to prevent the keyring lists from disappearing on us |
314 | * - we return -EAGAIN if we didn't find any matching key | 330 | * - we return -EAGAIN if we didn't find any matching key |
315 | * - we return -ENOKEY if we only found negative matching keys | 331 | * - we return -ENOKEY if we only found negative matching keys |
316 | */ | 332 | */ |
317 | struct key *keyring_search_aux(struct key *keyring, | 333 | struct key *keyring_search_aux(struct key *keyring, |
334 | struct task_struct *context, | ||
318 | struct key_type *type, | 335 | struct key_type *type, |
319 | const void *description, | 336 | const void *description, |
320 | key_match_func_t match) | 337 | key_match_func_t match) |
321 | { | 338 | { |
322 | struct { | 339 | struct { |
323 | struct key *keyring; | 340 | struct keyring_list *keylist; |
324 | int kix; | 341 | int kix; |
325 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 342 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
326 | 343 | ||
@@ -328,13 +345,15 @@ struct key *keyring_search_aux(struct key *keyring, | |||
328 | struct timespec now; | 345 | struct timespec now; |
329 | struct key *key; | 346 | struct key *key; |
330 | long err; | 347 | long err; |
331 | int sp, psp, kix; | 348 | int sp, kix; |
332 | 349 | ||
333 | key_check(keyring); | 350 | key_check(keyring); |
334 | 351 | ||
352 | rcu_read_lock(); | ||
353 | |||
335 | /* top keyring must have search permission to begin the search */ | 354 | /* top keyring must have search permission to begin the search */ |
336 | key = ERR_PTR(-EACCES); | 355 | key = ERR_PTR(-EACCES); |
337 | if (!key_permission(keyring, KEY_SEARCH)) | 356 | if (!key_task_permission(keyring, context, KEY_SEARCH)) |
338 | goto error; | 357 | goto error; |
339 | 358 | ||
340 | key = ERR_PTR(-ENOTDIR); | 359 | key = ERR_PTR(-ENOTDIR); |
@@ -347,11 +366,10 @@ struct key *keyring_search_aux(struct key *keyring, | |||
347 | 366 | ||
348 | /* start processing a new keyring */ | 367 | /* start processing a new keyring */ |
349 | descend: | 368 | descend: |
350 | read_lock(&keyring->lock); | 369 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
351 | if (keyring->flags & KEY_FLAG_REVOKED) | ||
352 | goto not_this_keyring; | 370 | goto not_this_keyring; |
353 | 371 | ||
354 | keylist = keyring->payload.subscriptions; | 372 | keylist = rcu_dereference(keyring->payload.subscriptions); |
355 | if (!keylist) | 373 | if (!keylist) |
356 | goto not_this_keyring; | 374 | goto not_this_keyring; |
357 | 375 | ||
@@ -364,7 +382,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
364 | continue; | 382 | continue; |
365 | 383 | ||
366 | /* skip revoked keys and expired keys */ | 384 | /* skip revoked keys and expired keys */ |
367 | if (key->flags & KEY_FLAG_REVOKED) | 385 | if (test_bit(KEY_FLAG_REVOKED, &key->flags)) |
368 | continue; | 386 | continue; |
369 | 387 | ||
370 | if (key->expiry && now.tv_sec >= key->expiry) | 388 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -375,11 +393,11 @@ struct key *keyring_search_aux(struct key *keyring, | |||
375 | continue; | 393 | continue; |
376 | 394 | ||
377 | /* key must have search permissions */ | 395 | /* key must have search permissions */ |
378 | if (!key_permission(key, KEY_SEARCH)) | 396 | if (!key_task_permission(key, context, KEY_SEARCH)) |
379 | continue; | 397 | continue; |
380 | 398 | ||
381 | /* we set a different error code if we find a negative key */ | 399 | /* we set a different error code if we find a negative key */ |
382 | if (key->flags & KEY_FLAG_NEGATIVE) { | 400 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
383 | err = -ENOKEY; | 401 | err = -ENOKEY; |
384 | continue; | 402 | continue; |
385 | } | 403 | } |
@@ -390,48 +408,37 @@ struct key *keyring_search_aux(struct key *keyring, | |||
390 | /* search through the keyrings nested in this one */ | 408 | /* search through the keyrings nested in this one */ |
391 | kix = 0; | 409 | kix = 0; |
392 | ascend: | 410 | ascend: |
393 | while (kix < keylist->nkeys) { | 411 | for (; kix < keylist->nkeys; kix++) { |
394 | key = keylist->keys[kix]; | 412 | key = keylist->keys[kix]; |
395 | if (key->type != &key_type_keyring) | 413 | if (key->type != &key_type_keyring) |
396 | goto next; | 414 | continue; |
397 | 415 | ||
398 | /* recursively search nested keyrings | 416 | /* recursively search nested keyrings |
399 | * - only search keyrings for which we have search permission | 417 | * - only search keyrings for which we have search permission |
400 | */ | 418 | */ |
401 | if (sp >= KEYRING_SEARCH_MAX_DEPTH) | 419 | if (sp >= KEYRING_SEARCH_MAX_DEPTH) |
402 | goto next; | 420 | continue; |
403 | |||
404 | if (!key_permission(key, KEY_SEARCH)) | ||
405 | goto next; | ||
406 | 421 | ||
407 | /* evade loops in the keyring tree */ | 422 | if (!key_task_permission(key, context, KEY_SEARCH)) |
408 | for (psp = 0; psp < sp; psp++) | 423 | continue; |
409 | if (stack[psp].keyring == keyring) | ||
410 | goto next; | ||
411 | 424 | ||
412 | /* stack the current position */ | 425 | /* stack the current position */ |
413 | stack[sp].keyring = keyring; | 426 | stack[sp].keylist = keylist; |
414 | stack[sp].kix = kix; | 427 | stack[sp].kix = kix; |
415 | sp++; | 428 | sp++; |
416 | 429 | ||
417 | /* begin again with the new keyring */ | 430 | /* begin again with the new keyring */ |
418 | keyring = key; | 431 | keyring = key; |
419 | goto descend; | 432 | goto descend; |
420 | |||
421 | next: | ||
422 | kix++; | ||
423 | } | 433 | } |
424 | 434 | ||
425 | /* the keyring we're looking at was disqualified or didn't contain a | 435 | /* the keyring we're looking at was disqualified or didn't contain a |
426 | * matching key */ | 436 | * matching key */ |
427 | not_this_keyring: | 437 | not_this_keyring: |
428 | read_unlock(&keyring->lock); | ||
429 | |||
430 | if (sp > 0) { | 438 | if (sp > 0) { |
431 | /* resume the processing of a keyring higher up in the tree */ | 439 | /* resume the processing of a keyring higher up in the tree */ |
432 | sp--; | 440 | sp--; |
433 | keyring = stack[sp].keyring; | 441 | keylist = stack[sp].keylist; |
434 | keylist = keyring->payload.subscriptions; | ||
435 | kix = stack[sp].kix + 1; | 442 | kix = stack[sp].kix + 1; |
436 | goto ascend; | 443 | goto ascend; |
437 | } | 444 | } |
@@ -442,16 +449,9 @@ struct key *keyring_search_aux(struct key *keyring, | |||
442 | /* we found a viable match */ | 449 | /* we found a viable match */ |
443 | found: | 450 | found: |
444 | atomic_inc(&key->usage); | 451 | atomic_inc(&key->usage); |
445 | read_unlock(&keyring->lock); | ||
446 | |||
447 | /* unwind the keyring stack */ | ||
448 | while (sp > 0) { | ||
449 | sp--; | ||
450 | read_unlock(&stack[sp].keyring->lock); | ||
451 | } | ||
452 | |||
453 | key_check(key); | 452 | key_check(key); |
454 | error: | 453 | error: |
454 | rcu_read_unlock(); | ||
455 | return key; | 455 | return key; |
456 | 456 | ||
457 | } /* end keyring_search_aux() */ | 457 | } /* end keyring_search_aux() */ |
@@ -469,7 +469,11 @@ struct key *keyring_search(struct key *keyring, | |||
469 | struct key_type *type, | 469 | struct key_type *type, |
470 | const char *description) | 470 | const char *description) |
471 | { | 471 | { |
472 | return keyring_search_aux(keyring, type, description, type->match); | 472 | if (!type->match) |
473 | return ERR_PTR(-ENOKEY); | ||
474 | |||
475 | return keyring_search_aux(keyring, current, | ||
476 | type, description, type->match); | ||
473 | 477 | ||
474 | } /* end keyring_search() */ | 478 | } /* end keyring_search() */ |
475 | 479 | ||
@@ -489,15 +493,18 @@ struct key *__keyring_search_one(struct key *keyring, | |||
489 | struct key *key; | 493 | struct key *key; |
490 | int loop; | 494 | int loop; |
491 | 495 | ||
492 | klist = keyring->payload.subscriptions; | 496 | rcu_read_lock(); |
497 | |||
498 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
493 | if (klist) { | 499 | if (klist) { |
494 | for (loop = 0; loop < klist->nkeys; loop++) { | 500 | for (loop = 0; loop < klist->nkeys; loop++) { |
495 | key = klist->keys[loop]; | 501 | key = klist->keys[loop]; |
496 | 502 | ||
497 | if (key->type == ktype && | 503 | if (key->type == ktype && |
498 | key->type->match(key, description) && | 504 | (!key->type->match || |
505 | key->type->match(key, description)) && | ||
499 | key_permission(key, perm) && | 506 | key_permission(key, perm) && |
500 | !(key->flags & KEY_FLAG_REVOKED) | 507 | !test_bit(KEY_FLAG_REVOKED, &key->flags) |
501 | ) | 508 | ) |
502 | goto found; | 509 | goto found; |
503 | } | 510 | } |
@@ -509,12 +516,58 @@ struct key *__keyring_search_one(struct key *keyring, | |||
509 | found: | 516 | found: |
510 | atomic_inc(&key->usage); | 517 | atomic_inc(&key->usage); |
511 | error: | 518 | error: |
519 | rcu_read_unlock(); | ||
512 | return key; | 520 | return key; |
513 | 521 | ||
514 | } /* end __keyring_search_one() */ | 522 | } /* end __keyring_search_one() */ |
515 | 523 | ||
516 | /*****************************************************************************/ | 524 | /*****************************************************************************/ |
517 | /* | 525 | /* |
526 | * search for an instantiation authorisation key matching a target key | ||
527 | * - the RCU read lock must be held by the caller | ||
528 | * - a target_id of zero specifies any valid token | ||
529 | */ | ||
530 | struct key *keyring_search_instkey(struct key *keyring, | ||
531 | key_serial_t target_id) | ||
532 | { | ||
533 | struct request_key_auth *rka; | ||
534 | struct keyring_list *klist; | ||
535 | struct key *instkey; | ||
536 | int loop; | ||
537 | |||
538 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
539 | if (klist) { | ||
540 | for (loop = 0; loop < klist->nkeys; loop++) { | ||
541 | instkey = klist->keys[loop]; | ||
542 | |||
543 | if (instkey->type != &key_type_request_key_auth) | ||
544 | continue; | ||
545 | |||
546 | rka = instkey->payload.data; | ||
547 | if (target_id && rka->target_key->serial != target_id) | ||
548 | continue; | ||
549 | |||
550 | /* the auth key is revoked during instantiation */ | ||
551 | if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags)) | ||
552 | goto found; | ||
553 | |||
554 | instkey = ERR_PTR(-EKEYREVOKED); | ||
555 | goto error; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | instkey = ERR_PTR(-EACCES); | ||
560 | goto error; | ||
561 | |||
562 | found: | ||
563 | atomic_inc(&instkey->usage); | ||
564 | error: | ||
565 | return instkey; | ||
566 | |||
567 | } /* end keyring_search_instkey() */ | ||
568 | |||
569 | /*****************************************************************************/ | ||
570 | /* | ||
518 | * find a keyring with the specified name | 571 | * find a keyring with the specified name |
519 | * - all named keyrings are searched | 572 | * - all named keyrings are searched |
520 | * - only find keyrings with search permission for the process | 573 | * - only find keyrings with search permission for the process |
@@ -540,7 +593,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
540 | &keyring_name_hash[bucket], | 593 | &keyring_name_hash[bucket], |
541 | type_data.link | 594 | type_data.link |
542 | ) { | 595 | ) { |
543 | if (keyring->flags & KEY_FLAG_REVOKED) | 596 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
544 | continue; | 597 | continue; |
545 | 598 | ||
546 | if (strcmp(keyring->description, name) != 0) | 599 | if (strcmp(keyring->description, name) != 0) |
@@ -579,7 +632,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
579 | static int keyring_detect_cycle(struct key *A, struct key *B) | 632 | static int keyring_detect_cycle(struct key *A, struct key *B) |
580 | { | 633 | { |
581 | struct { | 634 | struct { |
582 | struct key *subtree; | 635 | struct keyring_list *keylist; |
583 | int kix; | 636 | int kix; |
584 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 637 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
585 | 638 | ||
@@ -587,20 +640,21 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
587 | struct key *subtree, *key; | 640 | struct key *subtree, *key; |
588 | int sp, kix, ret; | 641 | int sp, kix, ret; |
589 | 642 | ||
643 | rcu_read_lock(); | ||
644 | |||
590 | ret = -EDEADLK; | 645 | ret = -EDEADLK; |
591 | if (A == B) | 646 | if (A == B) |
592 | goto error; | 647 | goto cycle_detected; |
593 | 648 | ||
594 | subtree = B; | 649 | subtree = B; |
595 | sp = 0; | 650 | sp = 0; |
596 | 651 | ||
597 | /* start processing a new keyring */ | 652 | /* start processing a new keyring */ |
598 | descend: | 653 | descend: |
599 | read_lock(&subtree->lock); | 654 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) |
600 | if (subtree->flags & KEY_FLAG_REVOKED) | ||
601 | goto not_this_keyring; | 655 | goto not_this_keyring; |
602 | 656 | ||
603 | keylist = subtree->payload.subscriptions; | 657 | keylist = rcu_dereference(subtree->payload.subscriptions); |
604 | if (!keylist) | 658 | if (!keylist) |
605 | goto not_this_keyring; | 659 | goto not_this_keyring; |
606 | kix = 0; | 660 | kix = 0; |
@@ -619,7 +673,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
619 | goto too_deep; | 673 | goto too_deep; |
620 | 674 | ||
621 | /* stack the current position */ | 675 | /* stack the current position */ |
622 | stack[sp].subtree = subtree; | 676 | stack[sp].keylist = keylist; |
623 | stack[sp].kix = kix; | 677 | stack[sp].kix = kix; |
624 | sp++; | 678 | sp++; |
625 | 679 | ||
@@ -632,13 +686,10 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
632 | /* the keyring we're looking at was disqualified or didn't contain a | 686 | /* the keyring we're looking at was disqualified or didn't contain a |
633 | * matching key */ | 687 | * matching key */ |
634 | not_this_keyring: | 688 | not_this_keyring: |
635 | read_unlock(&subtree->lock); | ||
636 | |||
637 | if (sp > 0) { | 689 | if (sp > 0) { |
638 | /* resume the checking of a keyring higher up in the tree */ | 690 | /* resume the checking of a keyring higher up in the tree */ |
639 | sp--; | 691 | sp--; |
640 | subtree = stack[sp].subtree; | 692 | keylist = stack[sp].keylist; |
641 | keylist = subtree->payload.subscriptions; | ||
642 | kix = stack[sp].kix + 1; | 693 | kix = stack[sp].kix + 1; |
643 | goto ascend; | 694 | goto ascend; |
644 | } | 695 | } |
@@ -646,30 +697,36 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
646 | ret = 0; /* no cycles detected */ | 697 | ret = 0; /* no cycles detected */ |
647 | 698 | ||
648 | error: | 699 | error: |
700 | rcu_read_unlock(); | ||
649 | return ret; | 701 | return ret; |
650 | 702 | ||
651 | too_deep: | 703 | too_deep: |
652 | ret = -ELOOP; | 704 | ret = -ELOOP; |
653 | goto error_unwind; | 705 | goto error; |
706 | |||
654 | cycle_detected: | 707 | cycle_detected: |
655 | ret = -EDEADLK; | 708 | ret = -EDEADLK; |
656 | error_unwind: | ||
657 | read_unlock(&subtree->lock); | ||
658 | |||
659 | /* unwind the keyring stack */ | ||
660 | while (sp > 0) { | ||
661 | sp--; | ||
662 | read_unlock(&stack[sp].subtree->lock); | ||
663 | } | ||
664 | |||
665 | goto error; | 709 | goto error; |
666 | 710 | ||
667 | } /* end keyring_detect_cycle() */ | 711 | } /* end keyring_detect_cycle() */ |
668 | 712 | ||
669 | /*****************************************************************************/ | 713 | /*****************************************************************************/ |
670 | /* | 714 | /* |
715 | * dispose of a keyring list after the RCU grace period | ||
716 | */ | ||
717 | static void keyring_link_rcu_disposal(struct rcu_head *rcu) | ||
718 | { | ||
719 | struct keyring_list *klist = | ||
720 | container_of(rcu, struct keyring_list, rcu); | ||
721 | |||
722 | kfree(klist); | ||
723 | |||
724 | } /* end keyring_link_rcu_disposal() */ | ||
725 | |||
726 | /*****************************************************************************/ | ||
727 | /* | ||
671 | * link a key into to a keyring | 728 | * link a key into to a keyring |
672 | * - must be called with the keyring's semaphore held | 729 | * - must be called with the keyring's semaphore write-locked |
673 | */ | 730 | */ |
674 | int __key_link(struct key *keyring, struct key *key) | 731 | int __key_link(struct key *keyring, struct key *key) |
675 | { | 732 | { |
@@ -679,7 +736,7 @@ int __key_link(struct key *keyring, struct key *key) | |||
679 | int ret; | 736 | int ret; |
680 | 737 | ||
681 | ret = -EKEYREVOKED; | 738 | ret = -EKEYREVOKED; |
682 | if (keyring->flags & KEY_FLAG_REVOKED) | 739 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
683 | goto error; | 740 | goto error; |
684 | 741 | ||
685 | ret = -ENOTDIR; | 742 | ret = -ENOTDIR; |
@@ -710,9 +767,10 @@ int __key_link(struct key *keyring, struct key *key) | |||
710 | /* there's sufficient slack space to add directly */ | 767 | /* there's sufficient slack space to add directly */ |
711 | atomic_inc(&key->usage); | 768 | atomic_inc(&key->usage); |
712 | 769 | ||
713 | write_lock(&keyring->lock); | 770 | klist->keys[klist->nkeys] = key; |
714 | klist->keys[klist->nkeys++] = key; | 771 | smp_wmb(); |
715 | write_unlock(&keyring->lock); | 772 | klist->nkeys++; |
773 | smp_wmb(); | ||
716 | 774 | ||
717 | ret = 0; | 775 | ret = 0; |
718 | } | 776 | } |
@@ -723,6 +781,8 @@ int __key_link(struct key *keyring, struct key *key) | |||
723 | max += klist->maxkeys; | 781 | max += klist->maxkeys; |
724 | 782 | ||
725 | ret = -ENFILE; | 783 | ret = -ENFILE; |
784 | if (max > 65535) | ||
785 | goto error3; | ||
726 | size = sizeof(*klist) + sizeof(*key) * max; | 786 | size = sizeof(*klist) + sizeof(*key) * max; |
727 | if (size > PAGE_SIZE) | 787 | if (size > PAGE_SIZE) |
728 | goto error3; | 788 | goto error3; |
@@ -743,14 +803,13 @@ int __key_link(struct key *keyring, struct key *key) | |||
743 | 803 | ||
744 | /* add the key into the new space */ | 804 | /* add the key into the new space */ |
745 | atomic_inc(&key->usage); | 805 | atomic_inc(&key->usage); |
746 | |||
747 | write_lock(&keyring->lock); | ||
748 | keyring->payload.subscriptions = nklist; | ||
749 | nklist->keys[nklist->nkeys++] = key; | 806 | nklist->keys[nklist->nkeys++] = key; |
750 | write_unlock(&keyring->lock); | 807 | |
808 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
751 | 809 | ||
752 | /* dispose of the old keyring list */ | 810 | /* dispose of the old keyring list */ |
753 | kfree(klist); | 811 | if (klist) |
812 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); | ||
754 | 813 | ||
755 | ret = 0; | 814 | ret = 0; |
756 | } | 815 | } |
@@ -791,11 +850,26 @@ EXPORT_SYMBOL(key_link); | |||
791 | 850 | ||
792 | /*****************************************************************************/ | 851 | /*****************************************************************************/ |
793 | /* | 852 | /* |
853 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | ||
854 | * key | ||
855 | */ | ||
856 | static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | ||
857 | { | ||
858 | struct keyring_list *klist = | ||
859 | container_of(rcu, struct keyring_list, rcu); | ||
860 | |||
861 | key_put(klist->keys[klist->delkey]); | ||
862 | kfree(klist); | ||
863 | |||
864 | } /* end keyring_unlink_rcu_disposal() */ | ||
865 | |||
866 | /*****************************************************************************/ | ||
867 | /* | ||
794 | * unlink the first link to a key from a keyring | 868 | * unlink the first link to a key from a keyring |
795 | */ | 869 | */ |
796 | int key_unlink(struct key *keyring, struct key *key) | 870 | int key_unlink(struct key *keyring, struct key *key) |
797 | { | 871 | { |
798 | struct keyring_list *klist; | 872 | struct keyring_list *klist, *nklist; |
799 | int loop, ret; | 873 | int loop, ret; |
800 | 874 | ||
801 | key_check(keyring); | 875 | key_check(keyring); |
@@ -819,31 +893,45 @@ int key_unlink(struct key *keyring, struct key *key) | |||
819 | ret = -ENOENT; | 893 | ret = -ENOENT; |
820 | goto error; | 894 | goto error; |
821 | 895 | ||
822 | key_is_present: | 896 | key_is_present: |
897 | /* we need to copy the key list for RCU purposes */ | ||
898 | nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys, | ||
899 | GFP_KERNEL); | ||
900 | if (!nklist) | ||
901 | goto nomem; | ||
902 | nklist->maxkeys = klist->maxkeys; | ||
903 | nklist->nkeys = klist->nkeys - 1; | ||
904 | |||
905 | if (loop > 0) | ||
906 | memcpy(&nklist->keys[0], | ||
907 | &klist->keys[0], | ||
908 | loop * sizeof(klist->keys[0])); | ||
909 | |||
910 | if (loop < nklist->nkeys) | ||
911 | memcpy(&nklist->keys[loop], | ||
912 | &klist->keys[loop + 1], | ||
913 | (nklist->nkeys - loop) * sizeof(klist->keys[0])); | ||
914 | |||
823 | /* adjust the user's quota */ | 915 | /* adjust the user's quota */ |
824 | key_payload_reserve(keyring, | 916 | key_payload_reserve(keyring, |
825 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 917 | keyring->datalen - KEYQUOTA_LINK_BYTES); |
826 | 918 | ||
827 | /* shuffle down the key pointers | 919 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
828 | * - it might be worth shrinking the allocated memory, but that runs | ||
829 | * the risk of ENOMEM as we would have to copy | ||
830 | */ | ||
831 | write_lock(&keyring->lock); | ||
832 | 920 | ||
833 | klist->nkeys--; | 921 | up_write(&keyring->sem); |
834 | if (loop < klist->nkeys) | ||
835 | memcpy(&klist->keys[loop], | ||
836 | &klist->keys[loop + 1], | ||
837 | (klist->nkeys - loop) * sizeof(struct key *)); | ||
838 | 922 | ||
839 | write_unlock(&keyring->lock); | 923 | /* schedule for later cleanup */ |
924 | klist->delkey = loop; | ||
925 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | ||
840 | 926 | ||
841 | up_write(&keyring->sem); | ||
842 | key_put(key); | ||
843 | ret = 0; | 927 | ret = 0; |
844 | 928 | ||
845 | error: | 929 | error: |
846 | return ret; | 930 | return ret; |
931 | nomem: | ||
932 | ret = -ENOMEM; | ||
933 | up_write(&keyring->sem); | ||
934 | goto error; | ||
847 | 935 | ||
848 | } /* end key_unlink() */ | 936 | } /* end key_unlink() */ |
849 | 937 | ||
@@ -851,13 +939,32 @@ EXPORT_SYMBOL(key_unlink); | |||
851 | 939 | ||
852 | /*****************************************************************************/ | 940 | /*****************************************************************************/ |
853 | /* | 941 | /* |
942 | * dispose of a keyring list after the RCU grace period, releasing the keys it | ||
943 | * links to | ||
944 | */ | ||
945 | static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | ||
946 | { | ||
947 | struct keyring_list *klist; | ||
948 | int loop; | ||
949 | |||
950 | klist = container_of(rcu, struct keyring_list, rcu); | ||
951 | |||
952 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | ||
953 | key_put(klist->keys[loop]); | ||
954 | |||
955 | kfree(klist); | ||
956 | |||
957 | } /* end keyring_clear_rcu_disposal() */ | ||
958 | |||
959 | /*****************************************************************************/ | ||
960 | /* | ||
854 | * clear the specified process keyring | 961 | * clear the specified process keyring |
855 | * - implements keyctl(KEYCTL_CLEAR) | 962 | * - implements keyctl(KEYCTL_CLEAR) |
856 | */ | 963 | */ |
857 | int keyring_clear(struct key *keyring) | 964 | int keyring_clear(struct key *keyring) |
858 | { | 965 | { |
859 | struct keyring_list *klist; | 966 | struct keyring_list *klist; |
860 | int loop, ret; | 967 | int ret; |
861 | 968 | ||
862 | ret = -ENOTDIR; | 969 | ret = -ENOTDIR; |
863 | if (keyring->type == &key_type_keyring) { | 970 | if (keyring->type == &key_type_keyring) { |
@@ -870,20 +977,15 @@ int keyring_clear(struct key *keyring) | |||
870 | key_payload_reserve(keyring, | 977 | key_payload_reserve(keyring, |
871 | sizeof(struct keyring_list)); | 978 | sizeof(struct keyring_list)); |
872 | 979 | ||
873 | write_lock(&keyring->lock); | 980 | rcu_assign_pointer(keyring->payload.subscriptions, |
874 | keyring->payload.subscriptions = NULL; | 981 | NULL); |
875 | write_unlock(&keyring->lock); | ||
876 | } | 982 | } |
877 | 983 | ||
878 | up_write(&keyring->sem); | 984 | up_write(&keyring->sem); |
879 | 985 | ||
880 | /* free the keys after the locks have been dropped */ | 986 | /* free the keys after the locks have been dropped */ |
881 | if (klist) { | 987 | if (klist) |
882 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 988 | call_rcu(&klist->rcu, keyring_clear_rcu_disposal); |
883 | key_put(klist->keys[loop]); | ||
884 | |||
885 | kfree(klist); | ||
886 | } | ||
887 | 989 | ||
888 | ret = 0; | 990 | ret = 0; |
889 | } | 991 | } |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 91343b85c39c..c55cf1fd0826 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -140,7 +140,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
140 | 140 | ||
141 | now = current_kernel_time(); | 141 | now = current_kernel_time(); |
142 | 142 | ||
143 | read_lock(&key->lock); | 143 | rcu_read_lock(); |
144 | 144 | ||
145 | /* come up with a suitable timeout value */ | 145 | /* come up with a suitable timeout value */ |
146 | if (key->expiry == 0) { | 146 | if (key->expiry == 0) { |
@@ -164,14 +164,17 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
164 | sprintf(xbuf, "%luw", timo / (60*60*24*7)); | 164 | sprintf(xbuf, "%luw", timo / (60*60*24*7)); |
165 | } | 165 | } |
166 | 166 | ||
167 | #define showflag(KEY, LETTER, FLAG) \ | ||
168 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | ||
169 | |||
167 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ", | 170 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ", |
168 | key->serial, | 171 | key->serial, |
169 | key->flags & KEY_FLAG_INSTANTIATED ? 'I' : '-', | 172 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), |
170 | key->flags & KEY_FLAG_REVOKED ? 'R' : '-', | 173 | showflag(key, 'R', KEY_FLAG_REVOKED), |
171 | key->flags & KEY_FLAG_DEAD ? 'D' : '-', | 174 | showflag(key, 'D', KEY_FLAG_DEAD), |
172 | key->flags & KEY_FLAG_IN_QUOTA ? 'Q' : '-', | 175 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), |
173 | key->flags & KEY_FLAG_USER_CONSTRUCT ? 'U' : '-', | 176 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
174 | key->flags & KEY_FLAG_NEGATIVE ? 'N' : '-', | 177 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
175 | atomic_read(&key->usage), | 178 | atomic_read(&key->usage), |
176 | xbuf, | 179 | xbuf, |
177 | key->perm, | 180 | key->perm, |
@@ -179,11 +182,13 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
179 | key->gid, | 182 | key->gid, |
180 | key->type->name); | 183 | key->type->name); |
181 | 184 | ||
185 | #undef showflag | ||
186 | |||
182 | if (key->type->describe) | 187 | if (key->type->describe) |
183 | key->type->describe(key, m); | 188 | key->type->describe(key, m); |
184 | seq_putc(m, '\n'); | 189 | seq_putc(m, '\n'); |
185 | 190 | ||
186 | read_unlock(&key->lock); | 191 | rcu_read_unlock(); |
187 | 192 | ||
188 | return 0; | 193 | return 0; |
189 | 194 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 2eb0e471cd40..9b0369c5a223 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* process_keys.c: management of a process's keyrings | 1 | /* process_keys.c: management of a process's keyrings |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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 |
@@ -38,10 +38,9 @@ struct key root_user_keyring = { | |||
38 | .serial = 2, | 38 | .serial = 2, |
39 | .type = &key_type_keyring, | 39 | .type = &key_type_keyring, |
40 | .user = &root_key_user, | 40 | .user = &root_key_user, |
41 | .lock = RW_LOCK_UNLOCKED, | ||
42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | 41 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), |
43 | .perm = KEY_USR_ALL, | 42 | .perm = KEY_USR_ALL, |
44 | .flags = KEY_FLAG_INSTANTIATED, | 43 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
45 | .description = "_uid.0", | 44 | .description = "_uid.0", |
46 | #ifdef KEY_DEBUGGING | 45 | #ifdef KEY_DEBUGGING |
47 | .magic = KEY_DEBUG_MAGIC, | 46 | .magic = KEY_DEBUG_MAGIC, |
@@ -54,10 +53,9 @@ struct key root_session_keyring = { | |||
54 | .serial = 1, | 53 | .serial = 1, |
55 | .type = &key_type_keyring, | 54 | .type = &key_type_keyring, |
56 | .user = &root_key_user, | 55 | .user = &root_key_user, |
57 | .lock = RW_LOCK_UNLOCKED, | ||
58 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | 56 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), |
59 | .perm = KEY_USR_ALL, | 57 | .perm = KEY_USR_ALL, |
60 | .flags = KEY_FLAG_INSTANTIATED, | 58 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
61 | .description = "_uid_ses.0", | 59 | .description = "_uid_ses.0", |
62 | #ifdef KEY_DEBUGGING | 60 | #ifdef KEY_DEBUGGING |
63 | .magic = KEY_DEBUG_MAGIC, | 61 | .magic = KEY_DEBUG_MAGIC, |
@@ -167,7 +165,7 @@ int install_thread_keyring(struct task_struct *tsk) | |||
167 | /* | 165 | /* |
168 | * make sure a process keyring is installed | 166 | * make sure a process keyring is installed |
169 | */ | 167 | */ |
170 | static int install_process_keyring(struct task_struct *tsk) | 168 | int install_process_keyring(struct task_struct *tsk) |
171 | { | 169 | { |
172 | unsigned long flags; | 170 | unsigned long flags; |
173 | struct key *keyring; | 171 | struct key *keyring; |
@@ -183,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk) | |||
183 | goto error; | 181 | goto error; |
184 | } | 182 | } |
185 | 183 | ||
186 | /* attach or swap keyrings */ | 184 | /* attach keyring */ |
187 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 185 | spin_lock_irqsave(&tsk->sighand->siglock, flags); |
188 | if (!tsk->signal->process_keyring) { | 186 | if (!tsk->signal->process_keyring) { |
189 | tsk->signal->process_keyring = keyring; | 187 | tsk->signal->process_keyring = keyring; |
@@ -229,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk, | |||
229 | 227 | ||
230 | /* install the keyring */ | 228 | /* install the keyring */ |
231 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 229 | spin_lock_irqsave(&tsk->sighand->siglock, flags); |
232 | old = tsk->signal->session_keyring; | 230 | old = rcu_dereference(tsk->signal->session_keyring); |
233 | tsk->signal->session_keyring = keyring; | 231 | rcu_assign_pointer(tsk->signal->session_keyring, keyring); |
234 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 232 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); |
235 | 233 | ||
236 | ret = 0; | 234 | ret = 0; |
237 | 235 | ||
236 | /* we're using RCU on the pointer */ | ||
237 | synchronize_rcu(); | ||
238 | key_put(old); | 238 | key_put(old); |
239 | error: | 239 | error: |
240 | return ret; | 240 | return ret; |
@@ -247,8 +247,6 @@ static int install_session_keyring(struct task_struct *tsk, | |||
247 | */ | 247 | */ |
248 | int copy_thread_group_keys(struct task_struct *tsk) | 248 | int copy_thread_group_keys(struct task_struct *tsk) |
249 | { | 249 | { |
250 | unsigned long flags; | ||
251 | |||
252 | key_check(current->thread_group->session_keyring); | 250 | key_check(current->thread_group->session_keyring); |
253 | key_check(current->thread_group->process_keyring); | 251 | key_check(current->thread_group->process_keyring); |
254 | 252 | ||
@@ -256,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk) | |||
256 | tsk->signal->process_keyring = NULL; | 254 | tsk->signal->process_keyring = NULL; |
257 | 255 | ||
258 | /* same session keyring */ | 256 | /* same session keyring */ |
259 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 257 | rcu_read_lock(); |
260 | tsk->signal->session_keyring = | 258 | tsk->signal->session_keyring = |
261 | key_get(current->signal->session_keyring); | 259 | key_get(rcu_dereference(current->signal->session_keyring)); |
262 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 260 | rcu_read_unlock(); |
263 | 261 | ||
264 | return 0; | 262 | return 0; |
265 | 263 | ||
@@ -349,9 +347,7 @@ void key_fsuid_changed(struct task_struct *tsk) | |||
349 | /* update the ownership of the thread keyring */ | 347 | /* update the ownership of the thread keyring */ |
350 | if (tsk->thread_keyring) { | 348 | if (tsk->thread_keyring) { |
351 | down_write(&tsk->thread_keyring->sem); | 349 | down_write(&tsk->thread_keyring->sem); |
352 | write_lock(&tsk->thread_keyring->lock); | ||
353 | tsk->thread_keyring->uid = tsk->fsuid; | 350 | tsk->thread_keyring->uid = tsk->fsuid; |
354 | write_unlock(&tsk->thread_keyring->lock); | ||
355 | up_write(&tsk->thread_keyring->sem); | 351 | up_write(&tsk->thread_keyring->sem); |
356 | } | 352 | } |
357 | 353 | ||
@@ -366,9 +362,7 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
366 | /* update the ownership of the thread keyring */ | 362 | /* update the ownership of the thread keyring */ |
367 | if (tsk->thread_keyring) { | 363 | if (tsk->thread_keyring) { |
368 | down_write(&tsk->thread_keyring->sem); | 364 | down_write(&tsk->thread_keyring->sem); |
369 | write_lock(&tsk->thread_keyring->lock); | ||
370 | tsk->thread_keyring->gid = tsk->fsgid; | 365 | tsk->thread_keyring->gid = tsk->fsgid; |
371 | write_unlock(&tsk->thread_keyring->lock); | ||
372 | up_write(&tsk->thread_keyring->sem); | 366 | up_write(&tsk->thread_keyring->sem); |
373 | } | 367 | } |
374 | 368 | ||
@@ -382,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
382 | * - we return -EAGAIN if we didn't find any matching key | 376 | * - we return -EAGAIN if we didn't find any matching key |
383 | * - we return -ENOKEY if we found only negative matching keys | 377 | * - we return -ENOKEY if we found only negative matching keys |
384 | */ | 378 | */ |
385 | struct key *search_process_keyrings_aux(struct key_type *type, | 379 | struct key *search_process_keyrings(struct key_type *type, |
386 | const void *description, | 380 | const void *description, |
387 | key_match_func_t match) | 381 | key_match_func_t match, |
382 | struct task_struct *context) | ||
388 | { | 383 | { |
389 | struct task_struct *tsk = current; | 384 | struct request_key_auth *rka; |
390 | unsigned long flags; | 385 | struct key *key, *ret, *err, *instkey; |
391 | struct key *key, *ret, *err, *tmp; | ||
392 | 386 | ||
393 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 387 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
394 | * searchable, but we failed to find a key or we found a negative key; | 388 | * searchable, but we failed to find a key or we found a negative key; |
@@ -402,9 +396,9 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
402 | err = ERR_PTR(-EAGAIN); | 396 | err = ERR_PTR(-EAGAIN); |
403 | 397 | ||
404 | /* search the thread keyring first */ | 398 | /* search the thread keyring first */ |
405 | if (tsk->thread_keyring) { | 399 | if (context->thread_keyring) { |
406 | key = keyring_search_aux(tsk->thread_keyring, type, | 400 | key = keyring_search_aux(context->thread_keyring, |
407 | description, match); | 401 | context, type, description, match); |
408 | if (!IS_ERR(key)) | 402 | if (!IS_ERR(key)) |
409 | goto found; | 403 | goto found; |
410 | 404 | ||
@@ -422,9 +416,9 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
422 | } | 416 | } |
423 | 417 | ||
424 | /* search the process keyring second */ | 418 | /* search the process keyring second */ |
425 | if (tsk->signal->process_keyring) { | 419 | if (context->signal->process_keyring) { |
426 | key = keyring_search_aux(tsk->signal->process_keyring, | 420 | key = keyring_search_aux(context->signal->process_keyring, |
427 | type, description, match); | 421 | context, type, description, match); |
428 | if (!IS_ERR(key)) | 422 | if (!IS_ERR(key)) |
429 | goto found; | 423 | goto found; |
430 | 424 | ||
@@ -441,52 +435,93 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
441 | } | 435 | } |
442 | } | 436 | } |
443 | 437 | ||
444 | /* search the session keyring last */ | 438 | /* search the session keyring */ |
445 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 439 | if (context->signal->session_keyring) { |
440 | rcu_read_lock(); | ||
441 | key = keyring_search_aux( | ||
442 | rcu_dereference(context->signal->session_keyring), | ||
443 | context, type, description, match); | ||
444 | rcu_read_unlock(); | ||
446 | 445 | ||
447 | tmp = tsk->signal->session_keyring; | 446 | if (!IS_ERR(key)) |
448 | if (!tmp) | 447 | goto found; |
449 | tmp = tsk->user->session_keyring; | ||
450 | atomic_inc(&tmp->usage); | ||
451 | 448 | ||
452 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 449 | switch (PTR_ERR(key)) { |
450 | case -EAGAIN: /* no key */ | ||
451 | if (ret) | ||
452 | break; | ||
453 | case -ENOKEY: /* negative key */ | ||
454 | ret = key; | ||
455 | break; | ||
456 | default: | ||
457 | err = key; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | /* if this process has a session keyring and that has an | ||
462 | * instantiation authorisation key in the bottom level, then we | ||
463 | * also search the keyrings of the process mentioned there */ | ||
464 | if (context != current) | ||
465 | goto no_key; | ||
466 | |||
467 | rcu_read_lock(); | ||
468 | instkey = __keyring_search_one( | ||
469 | rcu_dereference(context->signal->session_keyring), | ||
470 | &key_type_request_key_auth, NULL, 0); | ||
471 | rcu_read_unlock(); | ||
472 | |||
473 | if (IS_ERR(instkey)) | ||
474 | goto no_key; | ||
475 | |||
476 | rka = instkey->payload.data; | ||
453 | 477 | ||
454 | key = keyring_search_aux(tmp, type, description, match); | 478 | key = search_process_keyrings(type, description, match, |
455 | key_put(tmp); | 479 | rka->context); |
456 | if (!IS_ERR(key)) | 480 | key_put(instkey); |
457 | goto found; | ||
458 | 481 | ||
459 | switch (PTR_ERR(key)) { | 482 | if (!IS_ERR(key)) |
460 | case -EAGAIN: /* no key */ | 483 | goto found; |
461 | if (ret) | 484 | |
485 | switch (PTR_ERR(key)) { | ||
486 | case -EAGAIN: /* no key */ | ||
487 | if (ret) | ||
488 | break; | ||
489 | case -ENOKEY: /* negative key */ | ||
490 | ret = key; | ||
462 | break; | 491 | break; |
463 | case -ENOKEY: /* negative key */ | 492 | default: |
464 | ret = key; | 493 | err = key; |
465 | break; | 494 | break; |
466 | default: | 495 | } |
467 | err = key; | 496 | } |
468 | break; | 497 | /* or search the user-session keyring */ |
498 | else { | ||
499 | key = keyring_search_aux(context->user->session_keyring, | ||
500 | context, type, description, match); | ||
501 | if (!IS_ERR(key)) | ||
502 | goto found; | ||
503 | |||
504 | switch (PTR_ERR(key)) { | ||
505 | case -EAGAIN: /* no key */ | ||
506 | if (ret) | ||
507 | break; | ||
508 | case -ENOKEY: /* negative key */ | ||
509 | ret = key; | ||
510 | break; | ||
511 | default: | ||
512 | err = key; | ||
513 | break; | ||
514 | } | ||
469 | } | 515 | } |
470 | 516 | ||
517 | |||
518 | no_key: | ||
471 | /* no key - decide on the error we're going to go for */ | 519 | /* no key - decide on the error we're going to go for */ |
472 | key = ret ? ret : err; | 520 | key = ret ? ret : err; |
473 | 521 | ||
474 | found: | 522 | found: |
475 | return key; | 523 | return key; |
476 | 524 | ||
477 | } /* end search_process_keyrings_aux() */ | ||
478 | |||
479 | /*****************************************************************************/ | ||
480 | /* | ||
481 | * search the process keyrings for the first matching key | ||
482 | * - we return -EAGAIN if we didn't find any matching key | ||
483 | * - we return -ENOKEY if we found only negative matching keys | ||
484 | */ | ||
485 | struct key *search_process_keyrings(struct key_type *type, | ||
486 | const char *description) | ||
487 | { | ||
488 | return search_process_keyrings_aux(type, description, type->match); | ||
489 | |||
490 | } /* end search_process_keyrings() */ | 525 | } /* end search_process_keyrings() */ |
491 | 526 | ||
492 | /*****************************************************************************/ | 527 | /*****************************************************************************/ |
@@ -495,72 +530,73 @@ struct key *search_process_keyrings(struct key_type *type, | |||
495 | * - don't create special keyrings unless so requested | 530 | * - don't create special keyrings unless so requested |
496 | * - partially constructed keys aren't found unless requested | 531 | * - partially constructed keys aren't found unless requested |
497 | */ | 532 | */ |
498 | struct key *lookup_user_key(key_serial_t id, int create, int partial, | 533 | struct key *lookup_user_key(struct task_struct *context, key_serial_t id, |
499 | key_perm_t perm) | 534 | int create, int partial, key_perm_t perm) |
500 | { | 535 | { |
501 | struct task_struct *tsk = current; | ||
502 | unsigned long flags; | ||
503 | struct key *key; | 536 | struct key *key; |
504 | int ret; | 537 | int ret; |
505 | 538 | ||
539 | if (!context) | ||
540 | context = current; | ||
541 | |||
506 | key = ERR_PTR(-ENOKEY); | 542 | key = ERR_PTR(-ENOKEY); |
507 | 543 | ||
508 | switch (id) { | 544 | switch (id) { |
509 | case KEY_SPEC_THREAD_KEYRING: | 545 | case KEY_SPEC_THREAD_KEYRING: |
510 | if (!tsk->thread_keyring) { | 546 | if (!context->thread_keyring) { |
511 | if (!create) | 547 | if (!create) |
512 | goto error; | 548 | goto error; |
513 | 549 | ||
514 | ret = install_thread_keyring(tsk); | 550 | ret = install_thread_keyring(context); |
515 | if (ret < 0) { | 551 | if (ret < 0) { |
516 | key = ERR_PTR(ret); | 552 | key = ERR_PTR(ret); |
517 | goto error; | 553 | goto error; |
518 | } | 554 | } |
519 | } | 555 | } |
520 | 556 | ||
521 | key = tsk->thread_keyring; | 557 | key = context->thread_keyring; |
522 | atomic_inc(&key->usage); | 558 | atomic_inc(&key->usage); |
523 | break; | 559 | break; |
524 | 560 | ||
525 | case KEY_SPEC_PROCESS_KEYRING: | 561 | case KEY_SPEC_PROCESS_KEYRING: |
526 | if (!tsk->signal->process_keyring) { | 562 | if (!context->signal->process_keyring) { |
527 | if (!create) | 563 | if (!create) |
528 | goto error; | 564 | goto error; |
529 | 565 | ||
530 | ret = install_process_keyring(tsk); | 566 | ret = install_process_keyring(context); |
531 | if (ret < 0) { | 567 | if (ret < 0) { |
532 | key = ERR_PTR(ret); | 568 | key = ERR_PTR(ret); |
533 | goto error; | 569 | goto error; |
534 | } | 570 | } |
535 | } | 571 | } |
536 | 572 | ||
537 | key = tsk->signal->process_keyring; | 573 | key = context->signal->process_keyring; |
538 | atomic_inc(&key->usage); | 574 | atomic_inc(&key->usage); |
539 | break; | 575 | break; |
540 | 576 | ||
541 | case KEY_SPEC_SESSION_KEYRING: | 577 | case KEY_SPEC_SESSION_KEYRING: |
542 | if (!tsk->signal->session_keyring) { | 578 | if (!context->signal->session_keyring) { |
543 | /* always install a session keyring upon access if one | 579 | /* always install a session keyring upon access if one |
544 | * doesn't exist yet */ | 580 | * doesn't exist yet */ |
545 | ret = install_session_keyring( | 581 | ret = install_session_keyring( |
546 | tsk, tsk->user->session_keyring); | 582 | context, context->user->session_keyring); |
547 | if (ret < 0) | 583 | if (ret < 0) |
548 | goto error; | 584 | goto error; |
549 | } | 585 | } |
550 | 586 | ||
551 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 587 | rcu_read_lock(); |
552 | key = tsk->signal->session_keyring; | 588 | key = rcu_dereference(context->signal->session_keyring); |
553 | atomic_inc(&key->usage); | 589 | atomic_inc(&key->usage); |
554 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 590 | rcu_read_unlock(); |
555 | break; | 591 | break; |
556 | 592 | ||
557 | case KEY_SPEC_USER_KEYRING: | 593 | case KEY_SPEC_USER_KEYRING: |
558 | key = tsk->user->uid_keyring; | 594 | key = context->user->uid_keyring; |
559 | atomic_inc(&key->usage); | 595 | atomic_inc(&key->usage); |
560 | break; | 596 | break; |
561 | 597 | ||
562 | case KEY_SPEC_USER_SESSION_KEYRING: | 598 | case KEY_SPEC_USER_SESSION_KEYRING: |
563 | key = tsk->user->session_keyring; | 599 | key = context->user->session_keyring; |
564 | atomic_inc(&key->usage); | 600 | atomic_inc(&key->usage); |
565 | break; | 601 | break; |
566 | 602 | ||
@@ -580,7 +616,7 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
580 | break; | 616 | break; |
581 | } | 617 | } |
582 | 618 | ||
583 | /* check the status and permissions */ | 619 | /* check the status */ |
584 | if (perm) { | 620 | if (perm) { |
585 | ret = key_validate(key); | 621 | ret = key_validate(key); |
586 | if (ret < 0) | 622 | if (ret < 0) |
@@ -588,11 +624,13 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
588 | } | 624 | } |
589 | 625 | ||
590 | ret = -EIO; | 626 | ret = -EIO; |
591 | if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED)) | 627 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
592 | goto invalid_key; | 628 | goto invalid_key; |
593 | 629 | ||
630 | /* check the permissions */ | ||
594 | ret = -EACCES; | 631 | ret = -EACCES; |
595 | if (!key_permission(key, perm)) | 632 | |
633 | if (!key_task_permission(key, context, perm)) | ||
596 | goto invalid_key; | 634 | goto invalid_key; |
597 | 635 | ||
598 | error: | 636 | error: |
@@ -615,7 +653,6 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
615 | long join_session_keyring(const char *name) | 653 | long join_session_keyring(const char *name) |
616 | { | 654 | { |
617 | struct task_struct *tsk = current; | 655 | struct task_struct *tsk = current; |
618 | unsigned long flags; | ||
619 | struct key *keyring; | 656 | struct key *keyring; |
620 | long ret; | 657 | long ret; |
621 | 658 | ||
@@ -625,9 +662,9 @@ long join_session_keyring(const char *name) | |||
625 | if (ret < 0) | 662 | if (ret < 0) |
626 | goto error; | 663 | goto error; |
627 | 664 | ||
628 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 665 | rcu_read_lock(); |
629 | ret = tsk->signal->session_keyring->serial; | 666 | ret = rcu_dereference(tsk->signal->session_keyring)->serial; |
630 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 667 | rcu_read_unlock(); |
631 | goto error; | 668 | goto error; |
632 | } | 669 | } |
633 | 670 | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 9705b1aeba5d..dfcd983af1fd 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* request_key.c: request a key from userspace | 1 | /* request_key.c: request a key from userspace |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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,6 +13,7 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/kmod.h> | 14 | #include <linux/kmod.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/keyctl.h> | ||
16 | #include "internal.h" | 17 | #include "internal.h" |
17 | 18 | ||
18 | struct key_construction { | 19 | struct key_construction { |
@@ -27,18 +28,26 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); | |||
27 | /* | 28 | /* |
28 | * request userspace finish the construction of a key | 29 | * request userspace finish the construction of a key |
29 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>" | 30 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>" |
30 | * - if callout_info is an empty string, it'll be rendered as a "-" instead | ||
31 | */ | 31 | */ |
32 | static int call_request_key(struct key *key, | 32 | static int call_request_key(struct key *key, |
33 | const char *op, | 33 | const char *op, |
34 | const char *callout_info) | 34 | const char *callout_info) |
35 | { | 35 | { |
36 | struct task_struct *tsk = current; | 36 | struct task_struct *tsk = current; |
37 | unsigned long flags; | ||
38 | key_serial_t prkey, sskey; | 37 | key_serial_t prkey, sskey; |
38 | struct key *session_keyring, *rkakey; | ||
39 | char *argv[10], *envp[3], uid_str[12], gid_str[12]; | 39 | char *argv[10], *envp[3], uid_str[12], gid_str[12]; |
40 | char key_str[12], keyring_str[3][12]; | 40 | char key_str[12], keyring_str[3][12]; |
41 | int i; | 41 | int ret, i; |
42 | |||
43 | kenter("{%d},%s,%s", key->serial, op, callout_info); | ||
44 | |||
45 | /* generate a new session keyring with an auth key in it */ | ||
46 | session_keyring = request_key_auth_new(key, &rkakey); | ||
47 | if (IS_ERR(session_keyring)) { | ||
48 | ret = PTR_ERR(session_keyring); | ||
49 | goto error; | ||
50 | } | ||
42 | 51 | ||
43 | /* record the UID and GID */ | 52 | /* record the UID and GID */ |
44 | sprintf(uid_str, "%d", current->fsuid); | 53 | sprintf(uid_str, "%d", current->fsuid); |
@@ -55,17 +64,17 @@ static int call_request_key(struct key *key, | |||
55 | if (tsk->signal->process_keyring) | 64 | if (tsk->signal->process_keyring) |
56 | prkey = tsk->signal->process_keyring->serial; | 65 | prkey = tsk->signal->process_keyring->serial; |
57 | 66 | ||
58 | sskey = 0; | 67 | sprintf(keyring_str[1], "%d", prkey); |
59 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
60 | if (tsk->signal->session_keyring) | ||
61 | sskey = tsk->signal->session_keyring->serial; | ||
62 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
63 | |||
64 | 68 | ||
65 | if (!sskey) | 69 | if (tsk->signal->session_keyring) { |
70 | rcu_read_lock(); | ||
71 | sskey = rcu_dereference(tsk->signal->session_keyring)->serial; | ||
72 | rcu_read_unlock(); | ||
73 | } | ||
74 | else { | ||
66 | sskey = tsk->user->session_keyring->serial; | 75 | sskey = tsk->user->session_keyring->serial; |
76 | } | ||
67 | 77 | ||
68 | sprintf(keyring_str[1], "%d", prkey); | ||
69 | sprintf(keyring_str[2], "%d", sskey); | 78 | sprintf(keyring_str[2], "%d", sskey); |
70 | 79 | ||
71 | /* set up a minimal environment */ | 80 | /* set up a minimal environment */ |
@@ -84,11 +93,20 @@ static int call_request_key(struct key *key, | |||
84 | argv[i++] = keyring_str[0]; | 93 | argv[i++] = keyring_str[0]; |
85 | argv[i++] = keyring_str[1]; | 94 | argv[i++] = keyring_str[1]; |
86 | argv[i++] = keyring_str[2]; | 95 | argv[i++] = keyring_str[2]; |
87 | argv[i++] = callout_info[0] ? (char *) callout_info : "-"; | 96 | argv[i++] = (char *) callout_info; |
88 | argv[i] = NULL; | 97 | argv[i] = NULL; |
89 | 98 | ||
90 | /* do it */ | 99 | /* do it */ |
91 | return call_usermodehelper(argv[0], argv, envp, 1); | 100 | ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1); |
101 | |||
102 | /* dispose of the special keys */ | ||
103 | key_revoke(rkakey); | ||
104 | key_put(rkakey); | ||
105 | key_put(session_keyring); | ||
106 | |||
107 | error: | ||
108 | kleave(" = %d", ret); | ||
109 | return ret; | ||
92 | 110 | ||
93 | } /* end call_request_key() */ | 111 | } /* end call_request_key() */ |
94 | 112 | ||
@@ -105,7 +123,9 @@ static struct key *__request_key_construction(struct key_type *type, | |||
105 | struct key_construction cons; | 123 | struct key_construction cons; |
106 | struct timespec now; | 124 | struct timespec now; |
107 | struct key *key; | 125 | struct key *key; |
108 | int ret, negative; | 126 | int ret, negated; |
127 | |||
128 | kenter("%s,%s,%s", type->name, description, callout_info); | ||
109 | 129 | ||
110 | /* create a key and add it to the queue */ | 130 | /* create a key and add it to the queue */ |
111 | key = key_alloc(type, description, | 131 | key = key_alloc(type, description, |
@@ -113,9 +133,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
113 | if (IS_ERR(key)) | 133 | if (IS_ERR(key)) |
114 | goto alloc_failed; | 134 | goto alloc_failed; |
115 | 135 | ||
116 | write_lock(&key->lock); | 136 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
117 | key->flags |= KEY_FLAG_USER_CONSTRUCT; | ||
118 | write_unlock(&key->lock); | ||
119 | 137 | ||
120 | cons.key = key; | 138 | cons.key = key; |
121 | list_add_tail(&cons.link, &key->user->consq); | 139 | list_add_tail(&cons.link, &key->user->consq); |
@@ -130,7 +148,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
130 | 148 | ||
131 | /* if the key wasn't instantiated, then we want to give an error */ | 149 | /* if the key wasn't instantiated, then we want to give an error */ |
132 | ret = -ENOKEY; | 150 | ret = -ENOKEY; |
133 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) | 151 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
134 | goto request_failed; | 152 | goto request_failed; |
135 | 153 | ||
136 | down_write(&key_construction_sem); | 154 | down_write(&key_construction_sem); |
@@ -139,12 +157,13 @@ static struct key *__request_key_construction(struct key_type *type, | |||
139 | 157 | ||
140 | /* also give an error if the key was negatively instantiated */ | 158 | /* also give an error if the key was negatively instantiated */ |
141 | check_not_negative: | 159 | check_not_negative: |
142 | if (key->flags & KEY_FLAG_NEGATIVE) { | 160 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
143 | key_put(key); | 161 | key_put(key); |
144 | key = ERR_PTR(-ENOKEY); | 162 | key = ERR_PTR(-ENOKEY); |
145 | } | 163 | } |
146 | 164 | ||
147 | out: | 165 | out: |
166 | kleave(" = %p", key); | ||
148 | return key; | 167 | return key; |
149 | 168 | ||
150 | request_failed: | 169 | request_failed: |
@@ -152,24 +171,23 @@ static struct key *__request_key_construction(struct key_type *type, | |||
152 | * - remove from construction queue | 171 | * - remove from construction queue |
153 | * - mark the key as dead | 172 | * - mark the key as dead |
154 | */ | 173 | */ |
155 | negative = 0; | 174 | negated = 0; |
156 | down_write(&key_construction_sem); | 175 | down_write(&key_construction_sem); |
157 | 176 | ||
158 | list_del(&cons.link); | 177 | list_del(&cons.link); |
159 | 178 | ||
160 | write_lock(&key->lock); | ||
161 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
162 | |||
163 | /* check it didn't get instantiated between the check and the down */ | 179 | /* check it didn't get instantiated between the check and the down */ |
164 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 180 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
165 | key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; | 181 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
166 | negative = 1; | 182 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
183 | negated = 1; | ||
167 | } | 184 | } |
168 | 185 | ||
169 | write_unlock(&key->lock); | 186 | clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
187 | |||
170 | up_write(&key_construction_sem); | 188 | up_write(&key_construction_sem); |
171 | 189 | ||
172 | if (!negative) | 190 | if (!negated) |
173 | goto check_not_negative; /* surprisingly, the key got | 191 | goto check_not_negative; /* surprisingly, the key got |
174 | * instantiated */ | 192 | * instantiated */ |
175 | 193 | ||
@@ -178,13 +196,12 @@ static struct key *__request_key_construction(struct key_type *type, | |||
178 | key->expiry = now.tv_sec + key_negative_timeout; | 196 | key->expiry = now.tv_sec + key_negative_timeout; |
179 | 197 | ||
180 | if (current->signal->session_keyring) { | 198 | if (current->signal->session_keyring) { |
181 | unsigned long flags; | ||
182 | struct key *keyring; | 199 | struct key *keyring; |
183 | 200 | ||
184 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 201 | rcu_read_lock(); |
185 | keyring = current->signal->session_keyring; | 202 | keyring = rcu_dereference(current->signal->session_keyring); |
186 | atomic_inc(&keyring->usage); | 203 | atomic_inc(&keyring->usage); |
187 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 204 | rcu_read_unlock(); |
188 | 205 | ||
189 | key_link(keyring, key); | 206 | key_link(keyring, key); |
190 | key_put(keyring); | 207 | key_put(keyring); |
@@ -220,6 +237,9 @@ static struct key *request_key_construction(struct key_type *type, | |||
220 | 237 | ||
221 | DECLARE_WAITQUEUE(myself, current); | 238 | DECLARE_WAITQUEUE(myself, current); |
222 | 239 | ||
240 | kenter("%s,%s,{%d},%s", | ||
241 | type->name, description, user->uid, callout_info); | ||
242 | |||
223 | /* see if there's such a key under construction already */ | 243 | /* see if there's such a key under construction already */ |
224 | down_write(&key_construction_sem); | 244 | down_write(&key_construction_sem); |
225 | 245 | ||
@@ -236,6 +256,7 @@ static struct key *request_key_construction(struct key_type *type, | |||
236 | /* see about getting userspace to construct the key */ | 256 | /* see about getting userspace to construct the key */ |
237 | key = __request_key_construction(type, description, callout_info); | 257 | key = __request_key_construction(type, description, callout_info); |
238 | error: | 258 | error: |
259 | kleave(" = %p", key); | ||
239 | return key; | 260 | return key; |
240 | 261 | ||
241 | /* someone else has the same key under construction | 262 | /* someone else has the same key under construction |
@@ -249,8 +270,10 @@ static struct key *request_key_construction(struct key_type *type, | |||
249 | add_wait_queue(&request_key_conswq, &myself); | 270 | add_wait_queue(&request_key_conswq, &myself); |
250 | 271 | ||
251 | for (;;) { | 272 | for (;;) { |
252 | set_current_state(TASK_UNINTERRUPTIBLE); | 273 | set_current_state(TASK_INTERRUPTIBLE); |
253 | if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT)) | 274 | if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags)) |
275 | break; | ||
276 | if (signal_pending(current)) | ||
254 | break; | 277 | break; |
255 | schedule(); | 278 | schedule(); |
256 | } | 279 | } |
@@ -271,21 +294,83 @@ static struct key *request_key_construction(struct key_type *type, | |||
271 | 294 | ||
272 | /*****************************************************************************/ | 295 | /*****************************************************************************/ |
273 | /* | 296 | /* |
297 | * link a freshly minted key to an appropriate destination keyring | ||
298 | */ | ||
299 | static void request_key_link(struct key *key, struct key *dest_keyring) | ||
300 | { | ||
301 | struct task_struct *tsk = current; | ||
302 | struct key *drop = NULL; | ||
303 | |||
304 | kenter("{%d},%p", key->serial, dest_keyring); | ||
305 | |||
306 | /* find the appropriate keyring */ | ||
307 | if (!dest_keyring) { | ||
308 | switch (tsk->jit_keyring) { | ||
309 | case KEY_REQKEY_DEFL_DEFAULT: | ||
310 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | ||
311 | dest_keyring = tsk->thread_keyring; | ||
312 | if (dest_keyring) | ||
313 | break; | ||
314 | |||
315 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | ||
316 | dest_keyring = tsk->signal->process_keyring; | ||
317 | if (dest_keyring) | ||
318 | break; | ||
319 | |||
320 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | ||
321 | rcu_read_lock(); | ||
322 | dest_keyring = key_get( | ||
323 | rcu_dereference(tsk->signal->session_keyring)); | ||
324 | rcu_read_unlock(); | ||
325 | drop = dest_keyring; | ||
326 | |||
327 | if (dest_keyring) | ||
328 | break; | ||
329 | |||
330 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | ||
331 | dest_keyring = current->user->session_keyring; | ||
332 | break; | ||
333 | |||
334 | case KEY_REQKEY_DEFL_USER_KEYRING: | ||
335 | dest_keyring = current->user->uid_keyring; | ||
336 | break; | ||
337 | |||
338 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | ||
339 | default: | ||
340 | BUG(); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /* and attach the key to it */ | ||
345 | key_link(dest_keyring, key); | ||
346 | |||
347 | key_put(drop); | ||
348 | |||
349 | kleave(""); | ||
350 | |||
351 | } /* end request_key_link() */ | ||
352 | |||
353 | /*****************************************************************************/ | ||
354 | /* | ||
274 | * request a key | 355 | * request a key |
275 | * - search the process's keyrings | 356 | * - search the process's keyrings |
276 | * - check the list of keys being created or updated | 357 | * - check the list of keys being created or updated |
277 | * - call out to userspace for a key if requested (supplementary info can be | 358 | * - call out to userspace for a key if supplementary info was provided |
278 | * passed) | 359 | * - cache the key in an appropriate keyring |
279 | */ | 360 | */ |
280 | struct key *request_key(struct key_type *type, | 361 | struct key *request_key_and_link(struct key_type *type, |
281 | const char *description, | 362 | const char *description, |
282 | const char *callout_info) | 363 | const char *callout_info, |
364 | struct key *dest_keyring) | ||
283 | { | 365 | { |
284 | struct key_user *user; | 366 | struct key_user *user; |
285 | struct key *key; | 367 | struct key *key; |
286 | 368 | ||
369 | kenter("%s,%s,%s,%p", | ||
370 | type->name, description, callout_info, dest_keyring); | ||
371 | |||
287 | /* search all the process keyrings for a key */ | 372 | /* search all the process keyrings for a key */ |
288 | key = search_process_keyrings_aux(type, description, type->match); | 373 | key = search_process_keyrings(type, description, type->match, current); |
289 | 374 | ||
290 | if (PTR_ERR(key) == -EAGAIN) { | 375 | if (PTR_ERR(key) == -EAGAIN) { |
291 | /* the search failed, but the keyrings were searchable, so we | 376 | /* the search failed, but the keyrings were searchable, so we |
@@ -296,12 +381,13 @@ struct key *request_key(struct key_type *type, | |||
296 | 381 | ||
297 | /* - get hold of the user's construction queue */ | 382 | /* - get hold of the user's construction queue */ |
298 | user = key_user_lookup(current->fsuid); | 383 | user = key_user_lookup(current->fsuid); |
299 | if (!user) { | 384 | if (!user) |
300 | key = ERR_PTR(-ENOMEM); | 385 | goto nomem; |
301 | goto error; | 386 | |
302 | } | 387 | do { |
388 | if (signal_pending(current)) | ||
389 | goto interrupted; | ||
303 | 390 | ||
304 | for (;;) { | ||
305 | /* ask userspace (returns NULL if it waited on a key | 391 | /* ask userspace (returns NULL if it waited on a key |
306 | * being constructed) */ | 392 | * being constructed) */ |
307 | key = request_key_construction(type, description, | 393 | key = request_key_construction(type, description, |
@@ -311,18 +397,46 @@ struct key *request_key(struct key_type *type, | |||
311 | 397 | ||
312 | /* someone else made the key we want, so we need to | 398 | /* someone else made the key we want, so we need to |
313 | * search again as it might now be available to us */ | 399 | * search again as it might now be available to us */ |
314 | key = search_process_keyrings_aux(type, description, | 400 | key = search_process_keyrings(type, description, |
315 | type->match); | 401 | type->match, current); |
316 | if (PTR_ERR(key) != -EAGAIN) | 402 | |
317 | break; | 403 | } while (PTR_ERR(key) == -EAGAIN); |
318 | } | ||
319 | 404 | ||
320 | key_user_put(user); | 405 | key_user_put(user); |
406 | |||
407 | /* link the new key into the appropriate keyring */ | ||
408 | if (!PTR_ERR(key)) | ||
409 | request_key_link(key, dest_keyring); | ||
321 | } | 410 | } |
322 | 411 | ||
323 | error: | 412 | error: |
413 | kleave(" = %p", key); | ||
324 | return key; | 414 | return key; |
325 | 415 | ||
416 | nomem: | ||
417 | key = ERR_PTR(-ENOMEM); | ||
418 | goto error; | ||
419 | |||
420 | interrupted: | ||
421 | key_user_put(user); | ||
422 | key = ERR_PTR(-EINTR); | ||
423 | goto error; | ||
424 | |||
425 | } /* end request_key_and_link() */ | ||
426 | |||
427 | /*****************************************************************************/ | ||
428 | /* | ||
429 | * request a key | ||
430 | * - search the process's keyrings | ||
431 | * - check the list of keys being created or updated | ||
432 | * - call out to userspace for a key if supplementary info was provided | ||
433 | */ | ||
434 | struct key *request_key(struct key_type *type, | ||
435 | const char *description, | ||
436 | const char *callout_info) | ||
437 | { | ||
438 | return request_key_and_link(type, description, callout_info, NULL); | ||
439 | |||
326 | } /* end request_key() */ | 440 | } /* end request_key() */ |
327 | 441 | ||
328 | EXPORT_SYMBOL(request_key); | 442 | EXPORT_SYMBOL(request_key); |
@@ -339,7 +453,8 @@ int key_validate(struct key *key) | |||
339 | if (key) { | 453 | if (key) { |
340 | /* check it's still accessible */ | 454 | /* check it's still accessible */ |
341 | ret = -EKEYREVOKED; | 455 | ret = -EKEYREVOKED; |
342 | if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD)) | 456 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || |
457 | test_bit(KEY_FLAG_DEAD, &key->flags)) | ||
343 | goto error; | 458 | goto error; |
344 | 459 | ||
345 | /* check it hasn't expired */ | 460 | /* check it hasn't expired */ |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c new file mode 100644 index 000000000000..f22264632229 --- /dev/null +++ b/security/keys/request_key_auth.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* request_key_auth.c: request key authorisation controlling key def | ||
2 | * | ||
3 | * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include "internal.h" | ||
17 | |||
18 | static int request_key_auth_instantiate(struct key *, const void *, size_t); | ||
19 | static void request_key_auth_describe(const struct key *, struct seq_file *); | ||
20 | static void request_key_auth_destroy(struct key *); | ||
21 | |||
22 | /* | ||
23 | * the request-key authorisation key type definition | ||
24 | */ | ||
25 | struct key_type key_type_request_key_auth = { | ||
26 | .name = ".request_key_auth", | ||
27 | .def_datalen = sizeof(struct request_key_auth), | ||
28 | .instantiate = request_key_auth_instantiate, | ||
29 | .describe = request_key_auth_describe, | ||
30 | .destroy = request_key_auth_destroy, | ||
31 | }; | ||
32 | |||
33 | /*****************************************************************************/ | ||
34 | /* | ||
35 | * instantiate a request-key authorisation record | ||
36 | */ | ||
37 | static int request_key_auth_instantiate(struct key *key, | ||
38 | const void *data, | ||
39 | size_t datalen) | ||
40 | { | ||
41 | struct request_key_auth *rka, *irka; | ||
42 | struct key *instkey; | ||
43 | int ret; | ||
44 | |||
45 | ret = -ENOMEM; | ||
46 | rka = kmalloc(sizeof(*rka), GFP_KERNEL); | ||
47 | if (rka) { | ||
48 | /* see if the calling process is already servicing the key | ||
49 | * request of another process */ | ||
50 | instkey = key_get_instantiation_authkey(0); | ||
51 | if (!IS_ERR(instkey)) { | ||
52 | /* it is - use that instantiation context here too */ | ||
53 | irka = instkey->payload.data; | ||
54 | rka->context = irka->context; | ||
55 | rka->pid = irka->pid; | ||
56 | key_put(instkey); | ||
57 | } | ||
58 | else { | ||
59 | /* it isn't - use this process as the context */ | ||
60 | rka->context = current; | ||
61 | rka->pid = current->pid; | ||
62 | } | ||
63 | |||
64 | rka->target_key = key_get((struct key *) data); | ||
65 | key->payload.data = rka; | ||
66 | ret = 0; | ||
67 | } | ||
68 | |||
69 | return ret; | ||
70 | |||
71 | } /* end request_key_auth_instantiate() */ | ||
72 | |||
73 | /*****************************************************************************/ | ||
74 | /* | ||
75 | * | ||
76 | */ | ||
77 | static void request_key_auth_describe(const struct key *key, | ||
78 | struct seq_file *m) | ||
79 | { | ||
80 | struct request_key_auth *rka = key->payload.data; | ||
81 | |||
82 | seq_puts(m, "key:"); | ||
83 | seq_puts(m, key->description); | ||
84 | seq_printf(m, " pid:%d", rka->pid); | ||
85 | |||
86 | } /* end request_key_auth_describe() */ | ||
87 | |||
88 | /*****************************************************************************/ | ||
89 | /* | ||
90 | * destroy an instantiation authorisation token key | ||
91 | */ | ||
92 | static void request_key_auth_destroy(struct key *key) | ||
93 | { | ||
94 | struct request_key_auth *rka = key->payload.data; | ||
95 | |||
96 | kenter("{%d}", key->serial); | ||
97 | |||
98 | key_put(rka->target_key); | ||
99 | |||
100 | } /* end request_key_auth_destroy() */ | ||
101 | |||
102 | /*****************************************************************************/ | ||
103 | /* | ||
104 | * create a session keyring to be for the invokation of /sbin/request-key and | ||
105 | * stick an authorisation token in it | ||
106 | */ | ||
107 | struct key *request_key_auth_new(struct key *target, struct key **_rkakey) | ||
108 | { | ||
109 | struct key *keyring, *rkakey = NULL; | ||
110 | char desc[20]; | ||
111 | int ret; | ||
112 | |||
113 | kenter("%d,", target->serial); | ||
114 | |||
115 | /* allocate a new session keyring */ | ||
116 | sprintf(desc, "_req.%u", target->serial); | ||
117 | |||
118 | keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); | ||
119 | if (IS_ERR(keyring)) { | ||
120 | kleave("= %ld", PTR_ERR(keyring)); | ||
121 | return keyring; | ||
122 | } | ||
123 | |||
124 | /* allocate the auth key */ | ||
125 | sprintf(desc, "%x", target->serial); | ||
126 | |||
127 | rkakey = key_alloc(&key_type_request_key_auth, desc, | ||
128 | current->fsuid, current->fsgid, | ||
129 | KEY_USR_VIEW, 1); | ||
130 | if (IS_ERR(rkakey)) { | ||
131 | key_put(keyring); | ||
132 | kleave("= %ld", PTR_ERR(rkakey)); | ||
133 | return rkakey; | ||
134 | } | ||
135 | |||
136 | /* construct and attach to the keyring */ | ||
137 | ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL); | ||
138 | if (ret < 0) { | ||
139 | key_revoke(rkakey); | ||
140 | key_put(rkakey); | ||
141 | key_put(keyring); | ||
142 | kleave("= %d", ret); | ||
143 | return ERR_PTR(ret); | ||
144 | } | ||
145 | |||
146 | *_rkakey = rkakey; | ||
147 | kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial); | ||
148 | return keyring; | ||
149 | |||
150 | } /* end request_key_auth_new() */ | ||
151 | |||
152 | /*****************************************************************************/ | ||
153 | /* | ||
154 | * get the authorisation key for instantiation of a specific key if attached to | ||
155 | * the current process's keyrings | ||
156 | * - this key is inserted into a keyring and that is set as /sbin/request-key's | ||
157 | * session keyring | ||
158 | * - a target_id of zero specifies any valid token | ||
159 | */ | ||
160 | struct key *key_get_instantiation_authkey(key_serial_t target_id) | ||
161 | { | ||
162 | struct task_struct *tsk = current; | ||
163 | struct key *instkey; | ||
164 | |||
165 | /* we must have our own personal session keyring */ | ||
166 | if (!tsk->signal->session_keyring) | ||
167 | return ERR_PTR(-EACCES); | ||
168 | |||
169 | /* and it must contain a suitable request authorisation key | ||
170 | * - lock RCU against session keyring changing | ||
171 | */ | ||
172 | rcu_read_lock(); | ||
173 | |||
174 | instkey = keyring_search_instkey( | ||
175 | rcu_dereference(tsk->signal->session_keyring), target_id); | ||
176 | |||
177 | rcu_read_unlock(); | ||
178 | return instkey; | ||
179 | |||
180 | } /* end key_get_instantiation_authkey() */ | ||
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 8d65b3a28129..e446acba73d3 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
@@ -42,12 +42,21 @@ struct key_type key_type_user = { | |||
42 | .read = user_read, | 42 | .read = user_read, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | struct user_key_payload { | ||
46 | struct rcu_head rcu; /* RCU destructor */ | ||
47 | unsigned short datalen; /* length of this data */ | ||
48 | char data[0]; /* actual data */ | ||
49 | }; | ||
50 | |||
51 | EXPORT_SYMBOL_GPL(key_type_user); | ||
52 | |||
45 | /*****************************************************************************/ | 53 | /*****************************************************************************/ |
46 | /* | 54 | /* |
47 | * instantiate a user defined key | 55 | * instantiate a user defined key |
48 | */ | 56 | */ |
49 | static int user_instantiate(struct key *key, const void *data, size_t datalen) | 57 | static int user_instantiate(struct key *key, const void *data, size_t datalen) |
50 | { | 58 | { |
59 | struct user_key_payload *upayload; | ||
51 | int ret; | 60 | int ret; |
52 | 61 | ||
53 | ret = -EINVAL; | 62 | ret = -EINVAL; |
@@ -58,13 +67,15 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen) | |||
58 | if (ret < 0) | 67 | if (ret < 0) |
59 | goto error; | 68 | goto error; |
60 | 69 | ||
61 | /* attach the data */ | ||
62 | ret = -ENOMEM; | 70 | ret = -ENOMEM; |
63 | key->payload.data = kmalloc(datalen, GFP_KERNEL); | 71 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
64 | if (!key->payload.data) | 72 | if (!upayload) |
65 | goto error; | 73 | goto error; |
66 | 74 | ||
67 | memcpy(key->payload.data, data, datalen); | 75 | /* attach the data */ |
76 | upayload->datalen = datalen; | ||
77 | memcpy(upayload->data, data, datalen); | ||
78 | rcu_assign_pointer(key->payload.data, upayload); | ||
68 | ret = 0; | 79 | ret = 0; |
69 | 80 | ||
70 | error: | 81 | error: |
@@ -75,18 +86,25 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen) | |||
75 | /*****************************************************************************/ | 86 | /*****************************************************************************/ |
76 | /* | 87 | /* |
77 | * duplicate a user defined key | 88 | * duplicate a user defined key |
89 | * - both keys' semaphores are locked against further modification | ||
90 | * - the new key cannot yet be accessed | ||
78 | */ | 91 | */ |
79 | static int user_duplicate(struct key *key, const struct key *source) | 92 | static int user_duplicate(struct key *key, const struct key *source) |
80 | { | 93 | { |
94 | struct user_key_payload *upayload, *spayload; | ||
81 | int ret; | 95 | int ret; |
82 | 96 | ||
83 | /* just copy the payload */ | 97 | /* just copy the payload */ |
84 | ret = -ENOMEM; | 98 | ret = -ENOMEM; |
85 | key->payload.data = kmalloc(source->datalen, GFP_KERNEL); | 99 | upayload = kmalloc(sizeof(*upayload) + source->datalen, GFP_KERNEL); |
100 | if (upayload) { | ||
101 | spayload = rcu_dereference(source->payload.data); | ||
102 | BUG_ON(source->datalen != spayload->datalen); | ||
103 | |||
104 | upayload->datalen = key->datalen = spayload->datalen; | ||
105 | memcpy(upayload->data, spayload->data, key->datalen); | ||
86 | 106 | ||
87 | if (key->payload.data) { | 107 | key->payload.data = upayload; |
88 | key->datalen = source->datalen; | ||
89 | memcpy(key->payload.data, source->payload.data, source->datalen); | ||
90 | ret = 0; | 108 | ret = 0; |
91 | } | 109 | } |
92 | 110 | ||
@@ -96,40 +114,54 @@ static int user_duplicate(struct key *key, const struct key *source) | |||
96 | 114 | ||
97 | /*****************************************************************************/ | 115 | /*****************************************************************************/ |
98 | /* | 116 | /* |
117 | * dispose of the old data from an updated user defined key | ||
118 | */ | ||
119 | static void user_update_rcu_disposal(struct rcu_head *rcu) | ||
120 | { | ||
121 | struct user_key_payload *upayload; | ||
122 | |||
123 | upayload = container_of(rcu, struct user_key_payload, rcu); | ||
124 | |||
125 | kfree(upayload); | ||
126 | |||
127 | } /* end user_update_rcu_disposal() */ | ||
128 | |||
129 | /*****************************************************************************/ | ||
130 | /* | ||
99 | * update a user defined key | 131 | * update a user defined key |
132 | * - the key's semaphore is write-locked | ||
100 | */ | 133 | */ |
101 | static int user_update(struct key *key, const void *data, size_t datalen) | 134 | static int user_update(struct key *key, const void *data, size_t datalen) |
102 | { | 135 | { |
103 | void *new, *zap; | 136 | struct user_key_payload *upayload, *zap; |
104 | int ret; | 137 | int ret; |
105 | 138 | ||
106 | ret = -EINVAL; | 139 | ret = -EINVAL; |
107 | if (datalen <= 0 || datalen > 32767 || !data) | 140 | if (datalen <= 0 || datalen > 32767 || !data) |
108 | goto error; | 141 | goto error; |
109 | 142 | ||
110 | /* copy the data */ | 143 | /* construct a replacement payload */ |
111 | ret = -ENOMEM; | 144 | ret = -ENOMEM; |
112 | new = kmalloc(datalen, GFP_KERNEL); | 145 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
113 | if (!new) | 146 | if (!upayload) |
114 | goto error; | 147 | goto error; |
115 | 148 | ||
116 | memcpy(new, data, datalen); | 149 | upayload->datalen = datalen; |
150 | memcpy(upayload->data, data, datalen); | ||
117 | 151 | ||
118 | /* check the quota and attach the new data */ | 152 | /* check the quota and attach the new data */ |
119 | zap = new; | 153 | zap = upayload; |
120 | write_lock(&key->lock); | ||
121 | 154 | ||
122 | ret = key_payload_reserve(key, datalen); | 155 | ret = key_payload_reserve(key, datalen); |
123 | 156 | ||
124 | if (ret == 0) { | 157 | if (ret == 0) { |
125 | /* attach the new data, displacing the old */ | 158 | /* attach the new data, displacing the old */ |
126 | zap = key->payload.data; | 159 | zap = key->payload.data; |
127 | key->payload.data = new; | 160 | rcu_assign_pointer(key->payload.data, upayload); |
128 | key->expiry = 0; | 161 | key->expiry = 0; |
129 | } | 162 | } |
130 | 163 | ||
131 | write_unlock(&key->lock); | 164 | call_rcu(&zap->rcu, user_update_rcu_disposal); |
132 | kfree(zap); | ||
133 | 165 | ||
134 | error: | 166 | error: |
135 | return ret; | 167 | return ret; |
@@ -152,13 +184,15 @@ static int user_match(const struct key *key, const void *description) | |||
152 | */ | 184 | */ |
153 | static void user_destroy(struct key *key) | 185 | static void user_destroy(struct key *key) |
154 | { | 186 | { |
155 | kfree(key->payload.data); | 187 | struct user_key_payload *upayload = key->payload.data; |
188 | |||
189 | kfree(upayload); | ||
156 | 190 | ||
157 | } /* end user_destroy() */ | 191 | } /* end user_destroy() */ |
158 | 192 | ||
159 | /*****************************************************************************/ | 193 | /*****************************************************************************/ |
160 | /* | 194 | /* |
161 | * describe the user | 195 | * describe the user key |
162 | */ | 196 | */ |
163 | static void user_describe(const struct key *key, struct seq_file *m) | 197 | static void user_describe(const struct key *key, struct seq_file *m) |
164 | { | 198 | { |
@@ -171,18 +205,23 @@ static void user_describe(const struct key *key, struct seq_file *m) | |||
171 | /*****************************************************************************/ | 205 | /*****************************************************************************/ |
172 | /* | 206 | /* |
173 | * read the key data | 207 | * read the key data |
208 | * - the key's semaphore is read-locked | ||
174 | */ | 209 | */ |
175 | static long user_read(const struct key *key, | 210 | static long user_read(const struct key *key, |
176 | char __user *buffer, size_t buflen) | 211 | char __user *buffer, size_t buflen) |
177 | { | 212 | { |
178 | long ret = key->datalen; | 213 | struct user_key_payload *upayload; |
214 | long ret; | ||
215 | |||
216 | upayload = rcu_dereference(key->payload.data); | ||
217 | ret = upayload->datalen; | ||
179 | 218 | ||
180 | /* we can return the data as is */ | 219 | /* we can return the data as is */ |
181 | if (buffer && buflen > 0) { | 220 | if (buffer && buflen > 0) { |
182 | if (buflen > key->datalen) | 221 | if (buflen > upayload->datalen) |
183 | buflen = key->datalen; | 222 | buflen = upayload->datalen; |
184 | 223 | ||
185 | if (copy_to_user(buffer, key->payload.data, buflen) != 0) | 224 | if (copy_to_user(buffer, upayload->data, buflen) != 0) |
186 | ret = -EFAULT; | 225 | ret = -EFAULT; |
187 | } | 226 | } |
188 | 227 | ||