aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/keyring.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r--security/keys/keyring.c45
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 571out:
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 */
990static void keyring_revoke(struct key *keyring) 993static 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