aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-05 12:06:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-05 12:06:24 -0400
commit5f233706592fcce7df57e12674461c349b8f591d (patch)
tree386c1817cb1be85e532e034a9b1cb98776c35c81
parent8777c793d6a24c7f3adf52b1b1086e9706de4589 (diff)
parent896903c2f5f79f029388f033a00c3b813bc91201 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: KEYS: call_sbin_request_key() must write lock keyrings before modifying them KEYS: Use RCU dereference wrappers in keyring key type code KEYS: find_keyring_by_name() can gain access to a freed keyring
-rw-r--r--security/keys/keyring.c41
-rw-r--r--security/keys/request_key.c2
2 files changed, 23 insertions, 20 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index dd7cd0f8e13..1e4b0037935 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
@@ -201,8 +206,7 @@ static long keyring_read(const struct key *keyring,
201 int loop, ret; 206 int loop, ret;
202 207
203 ret = 0; 208 ret = 0;
204 klist = keyring->payload.subscriptions; 209 klist = rcu_dereference_locked_keyring(keyring);
205
206 if (klist) { 210 if (klist) {
207 /* calculate how much data we could return */ 211 /* calculate how much data we could return */
208 qty = klist->nkeys * sizeof(key_serial_t); 212 qty = klist->nkeys * sizeof(key_serial_t);
@@ -526,9 +530,8 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
526 struct key *keyring; 530 struct key *keyring;
527 int bucket; 531 int bucket;
528 532
529 keyring = ERR_PTR(-EINVAL);
530 if (!name) 533 if (!name)
531 goto error; 534 return ERR_PTR(-EINVAL);
532 535
533 bucket = keyring_hash(name); 536 bucket = keyring_hash(name);
534 537
@@ -555,17 +558,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
555 KEY_SEARCH) < 0) 558 KEY_SEARCH) < 0)
556 continue; 559 continue;
557 560
558 /* we've got a match */ 561 /* we've got a match but we might end up racing with
559 atomic_inc(&keyring->usage); 562 * key_cleanup() if the keyring is currently 'dead'
560 read_unlock(&keyring_name_lock); 563 * (ie. it has a zero usage count) */
561 goto error; 564 if (!atomic_inc_not_zero(&keyring->usage))
565 continue;
566 goto out;
562 } 567 }
563 } 568 }
564 569
565 read_unlock(&keyring_name_lock);
566 keyring = ERR_PTR(-ENOKEY); 570 keyring = ERR_PTR(-ENOKEY);
567 571out:
568 error: 572 read_unlock(&keyring_name_lock);
569 return keyring; 573 return keyring;
570 574
571} /* end find_keyring_by_name() */ 575} /* end find_keyring_by_name() */
@@ -720,8 +724,7 @@ int __key_link(struct key *keyring, struct key *key)
720 } 724 }
721 725
722 /* see if there's a matching key we can displace */ 726 /* see if there's a matching key we can displace */
723 klist = keyring->payload.subscriptions; 727 klist = rcu_dereference_locked_keyring(keyring);
724
725 if (klist && klist->nkeys > 0) { 728 if (klist && klist->nkeys > 0) {
726 struct key_type *type = key->type; 729 struct key_type *type = key->type;
727 730
@@ -765,8 +768,6 @@ int __key_link(struct key *keyring, struct key *key)
765 if (ret < 0) 768 if (ret < 0)
766 goto error2; 769 goto error2;
767 770
768 klist = keyring->payload.subscriptions;
769
770 if (klist && klist->nkeys < klist->maxkeys) { 771 if (klist && klist->nkeys < klist->maxkeys) {
771 /* there's sufficient slack space to add directly */ 772 /* there's sufficient slack space to add directly */
772 atomic_inc(&key->usage); 773 atomic_inc(&key->usage);
@@ -868,7 +869,7 @@ int key_unlink(struct key *keyring, struct key *key)
868 869
869 down_write(&keyring->sem); 870 down_write(&keyring->sem);
870 871
871 klist = keyring->payload.subscriptions; 872 klist = rcu_dereference_locked_keyring(keyring);
872 if (klist) { 873 if (klist) {
873 /* search the keyring for the key */ 874 /* search the keyring for the key */
874 for (loop = 0; loop < klist->nkeys; loop++) 875 for (loop = 0; loop < klist->nkeys; loop++)
@@ -959,7 +960,7 @@ int keyring_clear(struct key *keyring)
959 /* detach the pointer block with the locks held */ 960 /* detach the pointer block with the locks held */
960 down_write(&keyring->sem); 961 down_write(&keyring->sem);
961 962
962 klist = keyring->payload.subscriptions; 963 klist = rcu_dereference_locked_keyring(keyring);
963 if (klist) { 964 if (klist) {
964 /* adjust the quota */ 965 /* adjust the quota */
965 key_payload_reserve(keyring, 966 key_payload_reserve(keyring,
@@ -991,7 +992,9 @@ EXPORT_SYMBOL(keyring_clear);
991 */ 992 */
992static void keyring_revoke(struct key *keyring) 993static void keyring_revoke(struct key *keyring)
993{ 994{
994 struct keyring_list *klist = keyring->payload.subscriptions; 995 struct keyring_list *klist;
996
997 klist = rcu_dereference_locked_keyring(keyring);
995 998
996 /* adjust the quota */ 999 /* adjust the quota */
997 key_payload_reserve(keyring, 0); 1000 key_payload_reserve(keyring, 0);
@@ -1025,7 +1028,7 @@ void keyring_gc(struct key *keyring, time_t limit)
1025 1028
1026 down_write(&keyring->sem); 1029 down_write(&keyring->sem);
1027 1030
1028 klist = keyring->payload.subscriptions; 1031 klist = rcu_dereference_locked_keyring(keyring);
1029 if (!klist) 1032 if (!klist)
1030 goto no_klist; 1033 goto no_klist;
1031 1034
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index d737cea5347..d8c1a6a0fb0 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -94,7 +94,7 @@ static int call_sbin_request_key(struct key_construction *cons,
94 } 94 }
95 95
96 /* attach the auth key to the session keyring */ 96 /* attach the auth key to the session keyring */
97 ret = __key_link(keyring, authkey); 97 ret = key_link(keyring, authkey);
98 if (ret < 0) 98 if (ret < 0)
99 goto error_link; 99 goto error_link;
100 100