summaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-14 10:39:19 +1100
committerJames Morris <jmorris@namei.org>2008-11-14 10:39:19 +1100
commitc69e8d9c01db2adc503464993c358901c9af9de4 (patch)
treebed94aaa9aeb7a7834d1c880f72b62a11a752c78 /security/keys
parent86a264abe542cfececb4df129bc45a0338d8cdb9 (diff)
downloadlinux-c69e8d9c01db2adc503464993c358901c9af9de4.tar.gz
linux-c69e8d9c01db2adc503464993c358901c9af9de4.tar.bz2
linux-c69e8d9c01db2adc503464993c358901c9af9de4.zip
CRED: Use RCU to access another task's creds and to release a task's own creds
Use RCU to access another task's creds and to release a task's own creds. This means that it will be possible for the credentials of a task to be replaced without another task (a) requiring a full lock to read them, and (b) seeing deallocated memory. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/permission.c10
-rw-r--r--security/keys/process_keys.c24
2 files changed, 20 insertions, 14 deletions
diff --git a/security/keys/permission.c b/security/keys/permission.c
index baf3d5f31e71..13c36164f284 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -22,13 +22,16 @@ int key_task_permission(const key_ref_t key_ref,
struct task_struct *context,
key_perm_t perm)
{
- struct cred *cred = context->cred;
+ const struct cred *cred;
struct key *key;
key_perm_t kperm;
int ret;
key = key_ref_to_ptr(key_ref);
+ rcu_read_lock();
+ cred = __task_cred(context);
+
/* use the second 8-bits of permissions for keys the caller owns */
if (key->uid == cred->fsuid) {
kperm = key->perm >> 16;
@@ -43,10 +46,7 @@ int key_task_permission(const key_ref_t key_ref,
goto use_these_perms;
}
- spin_lock(&cred->lock);
ret = groups_search(cred->group_info, key->gid);
- spin_unlock(&cred->lock);
-
if (ret) {
kperm = key->perm >> 8;
goto use_these_perms;
@@ -57,6 +57,8 @@ int key_task_permission(const key_ref_t key_ref,
kperm = key->perm;
use_these_perms:
+ rcu_read_lock();
+
/* use the top 8-bits of permissions for keys the caller possesses
* - possessor permissions are additive with other permissions
*/
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index ce8ac6073d57..212601ebaa46 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -412,10 +412,13 @@ key_ref_t search_process_keyrings(struct key_type *type,
struct task_struct *context)
{
struct request_key_auth *rka;
+ struct cred *cred;
key_ref_t key_ref, ret, err;
might_sleep();
+ cred = get_task_cred(context);
+
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -428,9 +431,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */
- if (context->cred->thread_keyring) {
+ if (cred->thread_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->cred->thread_keyring, 1),
+ make_key_ref(cred->thread_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -495,9 +498,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
}
}
/* or search the user-session keyring */
- else if (context->cred->user->session_keyring) {
+ else if (cred->user->session_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->cred->user->session_keyring, 1),
+ make_key_ref(cred->user->session_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -519,20 +522,20 @@ key_ref_t search_process_keyrings(struct key_type *type,
* search the keyrings of the process mentioned there
* - we don't permit access to request_key auth keys via this method
*/
- if (context->cred->request_key_auth &&
+ if (cred->request_key_auth &&
context == current &&
type != &key_type_request_key_auth
) {
/* defend against the auth key being revoked */
- down_read(&context->cred->request_key_auth->sem);
+ down_read(&cred->request_key_auth->sem);
- if (key_validate(context->cred->request_key_auth) == 0) {
- rka = context->cred->request_key_auth->payload.data;
+ if (key_validate(cred->request_key_auth) == 0) {
+ rka = cred->request_key_auth->payload.data;
key_ref = search_process_keyrings(type, description,
match, rka->context);
- up_read(&context->cred->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);
if (!IS_ERR(key_ref))
goto found;
@@ -549,7 +552,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
break;
}
} else {
- up_read(&context->cred->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);
}
}
@@ -557,6 +560,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
key_ref = ret ? ret : err;
found:
+ put_cred(cred);
return key_ref;
} /* end search_process_keyrings() */