Commit 5f233706 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

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
parents 8777c793 896903c2
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h" #include "internal.h"
#define rcu_dereference_locked_keyring(keyring) \
(rcu_dereference_protected( \
(keyring)->payload.subscriptions, \
rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
/* /*
* when plumbing the depths of the key tree, this sets a hard limit set on how * when plumbing the depths of the key tree, this sets a hard limit set on how
* deep we're willing to go * deep we're willing to go
...@@ -201,8 +206,7 @@ static long keyring_read(const struct key *keyring, ...@@ -201,8 +206,7 @@ static long keyring_read(const struct key *keyring,
int loop, ret; int loop, ret;
ret = 0; ret = 0;
klist = keyring->payload.subscriptions; klist = rcu_dereference_locked_keyring(keyring);
if (klist) { if (klist) {
/* calculate how much data we could return */ /* calculate how much data we could return */
qty = klist->nkeys * sizeof(key_serial_t); 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,9 +530,8 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
struct key *keyring; struct key *keyring;
int bucket; int bucket;
keyring = ERR_PTR(-EINVAL);
if (!name) if (!name)
goto error; return ERR_PTR(-EINVAL);
bucket = keyring_hash(name); bucket = keyring_hash(name);
...@@ -555,17 +558,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) ...@@ -555,17 +558,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
KEY_SEARCH) < 0) KEY_SEARCH) < 0)
continue; continue;
/* we've got a match */ /* we've got a match but we might end up racing with
atomic_inc(&keyring->usage); * key_cleanup() if the keyring is currently 'dead'
read_unlock(&keyring_name_lock); * (ie. it has a zero usage count) */
goto error; if (!atomic_inc_not_zero(&keyring->usage))
continue;
goto out;
} }
} }
read_unlock(&keyring_name_lock);
keyring = ERR_PTR(-ENOKEY); keyring = ERR_PTR(-ENOKEY);
out:
error: read_unlock(&keyring_name_lock);
return keyring; return keyring;
} /* end find_keyring_by_name() */ } /* end find_keyring_by_name() */
...@@ -720,8 +724,7 @@ int __key_link(struct key *keyring, struct key *key) ...@@ -720,8 +724,7 @@ int __key_link(struct key *keyring, struct key *key)
} }
/* see if there's a matching key we can displace */ /* see if there's a matching key we can displace */
klist = keyring->payload.subscriptions; klist = rcu_dereference_locked_keyring(keyring);
if (klist && klist->nkeys > 0) { if (klist && klist->nkeys > 0) {
struct key_type *type = key->type; struct key_type *type = key->type;
...@@ -765,8 +768,6 @@ int __key_link(struct key *keyring, struct key *key) ...@@ -765,8 +768,6 @@ int __key_link(struct key *keyring, struct key *key)
if (ret < 0) if (ret < 0)
goto error2; goto error2;
klist = keyring->payload.subscriptions;
if (klist && klist->nkeys < klist->maxkeys) { if (klist && klist->nkeys < klist->maxkeys) {
/* there's sufficient slack space to add directly */ /* there's sufficient slack space to add directly */
atomic_inc(&key->usage); atomic_inc(&key->usage);
...@@ -868,7 +869,7 @@ int key_unlink(struct key *keyring, struct key *key) ...@@ -868,7 +869,7 @@ int key_unlink(struct key *keyring, struct key *key)
down_write(&keyring->sem); down_write(&keyring->sem);
klist = keyring->payload.subscriptions; klist = rcu_dereference_locked_keyring(keyring);
if (klist) { if (klist) {
/* search the keyring for the key */ /* search the keyring for the key */
for (loop = 0; loop < klist->nkeys; loop++) for (loop = 0; loop < klist->nkeys; loop++)
...@@ -959,7 +960,7 @@ int keyring_clear(struct key *keyring) ...@@ -959,7 +960,7 @@ int keyring_clear(struct key *keyring)
/* detach the pointer block with the locks held */ /* detach the pointer block with the locks held */
down_write(&keyring->sem); down_write(&keyring->sem);
klist = keyring->payload.subscriptions; klist = rcu_dereference_locked_keyring(keyring);
if (klist) { if (klist) {
/* adjust the quota */ /* adjust the quota */
key_payload_reserve(keyring, key_payload_reserve(keyring,
...@@ -991,7 +992,9 @@ EXPORT_SYMBOL(keyring_clear); ...@@ -991,7 +992,9 @@ EXPORT_SYMBOL(keyring_clear);
*/ */
static void keyring_revoke(struct key *keyring) static void keyring_revoke(struct key *keyring)
{ {
struct keyring_list *klist = keyring->payload.subscriptions; struct keyring_list *klist;
klist = rcu_dereference_locked_keyring(keyring);
/* adjust the quota */ /* adjust the quota */
key_payload_reserve(keyring, 0); key_payload_reserve(keyring, 0);
...@@ -1025,7 +1028,7 @@ void keyring_gc(struct key *keyring, time_t limit) ...@@ -1025,7 +1028,7 @@ void keyring_gc(struct key *keyring, time_t limit)
down_write(&keyring->sem); down_write(&keyring->sem);
klist = keyring->payload.subscriptions; klist = rcu_dereference_locked_keyring(keyring);
if (!klist) if (!klist)
goto no_klist; goto no_klist;
......
...@@ -94,7 +94,7 @@ static int call_sbin_request_key(struct key_construction *cons, ...@@ -94,7 +94,7 @@ static int call_sbin_request_key(struct key_construction *cons,
} }
/* attach the auth key to the session keyring */ /* attach the auth key to the session keyring */
ret = __key_link(keyring, authkey); ret = key_link(keyring, authkey);
if (ret < 0) if (ret < 0)
goto error_link; goto error_link;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment