diff options
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 8ec02746ca99..1e4b0037935c 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -20,6 +20,11 @@ | |||
20 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
21 | #include "internal.h" | 21 | #include "internal.h" |
22 | 22 | ||
23 | #define rcu_dereference_locked_keyring(keyring) \ | ||
24 | (rcu_dereference_protected( \ | ||
25 | (keyring)->payload.subscriptions, \ | ||
26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | ||
27 | |||
23 | /* | 28 | /* |
24 | * when plumbing the depths of the key tree, this sets a hard limit set on how | 29 | * when plumbing the depths of the key tree, this sets a hard limit set on how |
25 | * deep we're willing to go | 30 | * deep we're willing to go |
@@ -151,7 +156,9 @@ static void keyring_destroy(struct key *keyring) | |||
151 | write_unlock(&keyring_name_lock); | 156 | write_unlock(&keyring_name_lock); |
152 | } | 157 | } |
153 | 158 | ||
154 | klist = rcu_dereference(keyring->payload.subscriptions); | 159 | klist = rcu_dereference_check(keyring->payload.subscriptions, |
160 | rcu_read_lock_held() || | ||
161 | atomic_read(&keyring->usage) == 0); | ||
155 | if (klist) { | 162 | if (klist) { |
156 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 163 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
157 | key_put(klist->keys[loop]); | 164 | key_put(klist->keys[loop]); |
@@ -199,8 +206,7 @@ static long keyring_read(const struct key *keyring, | |||
199 | int loop, ret; | 206 | int loop, ret; |
200 | 207 | ||
201 | ret = 0; | 208 | ret = 0; |
202 | klist = rcu_dereference(keyring->payload.subscriptions); | 209 | klist = rcu_dereference_locked_keyring(keyring); |
203 | |||
204 | if (klist) { | 210 | if (klist) { |
205 | /* calculate how much data we could return */ | 211 | /* calculate how much data we could return */ |
206 | qty = klist->nkeys * sizeof(key_serial_t); | 212 | qty = klist->nkeys * sizeof(key_serial_t); |
@@ -524,9 +530,8 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
524 | struct key *keyring; | 530 | struct key *keyring; |
525 | int bucket; | 531 | int bucket; |
526 | 532 | ||
527 | keyring = ERR_PTR(-EINVAL); | ||
528 | if (!name) | 533 | if (!name) |
529 | goto error; | 534 | return ERR_PTR(-EINVAL); |
530 | 535 | ||
531 | bucket = keyring_hash(name); | 536 | bucket = keyring_hash(name); |
532 | 537 | ||
@@ -553,17 +558,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
553 | KEY_SEARCH) < 0) | 558 | KEY_SEARCH) < 0) |
554 | continue; | 559 | continue; |
555 | 560 | ||
556 | /* we've got a match */ | 561 | /* we've got a match but we might end up racing with |
557 | atomic_inc(&keyring->usage); | 562 | * key_cleanup() if the keyring is currently 'dead' |
558 | read_unlock(&keyring_name_lock); | 563 | * (ie. it has a zero usage count) */ |
559 | goto error; | 564 | if (!atomic_inc_not_zero(&keyring->usage)) |
565 | continue; | ||
566 | goto out; | ||
560 | } | 567 | } |
561 | } | 568 | } |
562 | 569 | ||
563 | read_unlock(&keyring_name_lock); | ||
564 | keyring = ERR_PTR(-ENOKEY); | 570 | keyring = ERR_PTR(-ENOKEY); |
565 | 571 | out: | |
566 | error: | 572 | read_unlock(&keyring_name_lock); |
567 | return keyring; | 573 | return keyring; |
568 | 574 | ||
569 | } /* end find_keyring_by_name() */ | 575 | } /* end find_keyring_by_name() */ |
@@ -718,8 +724,7 @@ int __key_link(struct key *keyring, struct key *key) | |||
718 | } | 724 | } |
719 | 725 | ||
720 | /* see if there's a matching key we can displace */ | 726 | /* see if there's a matching key we can displace */ |
721 | klist = keyring->payload.subscriptions; | 727 | klist = rcu_dereference_locked_keyring(keyring); |
722 | |||
723 | if (klist && klist->nkeys > 0) { | 728 | if (klist && klist->nkeys > 0) { |
724 | struct key_type *type = key->type; | 729 | struct key_type *type = key->type; |
725 | 730 | ||
@@ -763,8 +768,6 @@ int __key_link(struct key *keyring, struct key *key) | |||
763 | if (ret < 0) | 768 | if (ret < 0) |
764 | goto error2; | 769 | goto error2; |
765 | 770 | ||
766 | klist = keyring->payload.subscriptions; | ||
767 | |||
768 | if (klist && klist->nkeys < klist->maxkeys) { | 771 | if (klist && klist->nkeys < klist->maxkeys) { |
769 | /* there's sufficient slack space to add directly */ | 772 | /* there's sufficient slack space to add directly */ |
770 | atomic_inc(&key->usage); | 773 | atomic_inc(&key->usage); |
@@ -866,7 +869,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
866 | 869 | ||
867 | down_write(&keyring->sem); | 870 | down_write(&keyring->sem); |
868 | 871 | ||
869 | klist = keyring->payload.subscriptions; | 872 | klist = rcu_dereference_locked_keyring(keyring); |
870 | if (klist) { | 873 | if (klist) { |
871 | /* search the keyring for the key */ | 874 | /* search the keyring for the key */ |
872 | for (loop = 0; loop < klist->nkeys; loop++) | 875 | for (loop = 0; loop < klist->nkeys; loop++) |
@@ -957,7 +960,7 @@ int keyring_clear(struct key *keyring) | |||
957 | /* detach the pointer block with the locks held */ | 960 | /* detach the pointer block with the locks held */ |
958 | down_write(&keyring->sem); | 961 | down_write(&keyring->sem); |
959 | 962 | ||
960 | klist = keyring->payload.subscriptions; | 963 | klist = rcu_dereference_locked_keyring(keyring); |
961 | if (klist) { | 964 | if (klist) { |
962 | /* adjust the quota */ | 965 | /* adjust the quota */ |
963 | key_payload_reserve(keyring, | 966 | key_payload_reserve(keyring, |
@@ -989,7 +992,9 @@ EXPORT_SYMBOL(keyring_clear); | |||
989 | */ | 992 | */ |
990 | static void keyring_revoke(struct key *keyring) | 993 | static void keyring_revoke(struct key *keyring) |
991 | { | 994 | { |
992 | struct keyring_list *klist = keyring->payload.subscriptions; | 995 | struct keyring_list *klist; |
996 | |||
997 | klist = rcu_dereference_locked_keyring(keyring); | ||
993 | 998 | ||
994 | /* adjust the quota */ | 999 | /* adjust the quota */ |
995 | key_payload_reserve(keyring, 0); | 1000 | key_payload_reserve(keyring, 0); |
@@ -1023,7 +1028,7 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1023 | 1028 | ||
1024 | down_write(&keyring->sem); | 1029 | down_write(&keyring->sem); |
1025 | 1030 | ||
1026 | klist = keyring->payload.subscriptions; | 1031 | klist = rcu_dereference_locked_keyring(keyring); |
1027 | if (!klist) | 1032 | if (!klist) |
1028 | goto no_klist; | 1033 | goto no_klist; |
1029 | 1034 | ||