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
This commit is contained in:
commit
5f23370659
2 changed files with 23 additions and 20 deletions
|
@ -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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
/* 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);
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
|
|
Reference in a new issue