diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:19 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:19 -0500 |
commit | c69e8d9c01db2adc503464993c358901c9af9de4 (patch) | |
tree | bed94aaa9aeb7a7834d1c880f72b62a11a752c78 /security/keys | |
parent | 86a264abe542cfececb4df129bc45a0338d8cdb9 (diff) |
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.c | 10 | ||||
-rw-r--r-- | security/keys/process_keys.c | 24 |
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, | |||
22 | struct task_struct *context, | 22 | struct task_struct *context, |
23 | key_perm_t perm) | 23 | key_perm_t perm) |
24 | { | 24 | { |
25 | struct cred *cred = context->cred; | 25 | const struct cred *cred; |
26 | struct key *key; | 26 | struct key *key; |
27 | key_perm_t kperm; | 27 | key_perm_t kperm; |
28 | int ret; | 28 | int ret; |
29 | 29 | ||
30 | key = key_ref_to_ptr(key_ref); | 30 | key = key_ref_to_ptr(key_ref); |
31 | 31 | ||
32 | rcu_read_lock(); | ||
33 | cred = __task_cred(context); | ||
34 | |||
32 | /* use the second 8-bits of permissions for keys the caller owns */ | 35 | /* use the second 8-bits of permissions for keys the caller owns */ |
33 | if (key->uid == cred->fsuid) { | 36 | if (key->uid == cred->fsuid) { |
34 | kperm = key->perm >> 16; | 37 | kperm = key->perm >> 16; |
@@ -43,10 +46,7 @@ int key_task_permission(const key_ref_t key_ref, | |||
43 | goto use_these_perms; | 46 | goto use_these_perms; |
44 | } | 47 | } |
45 | 48 | ||
46 | spin_lock(&cred->lock); | ||
47 | ret = groups_search(cred->group_info, key->gid); | 49 | ret = groups_search(cred->group_info, key->gid); |
48 | spin_unlock(&cred->lock); | ||
49 | |||
50 | if (ret) { | 50 | if (ret) { |
51 | kperm = key->perm >> 8; | 51 | kperm = key->perm >> 8; |
52 | goto use_these_perms; | 52 | goto use_these_perms; |
@@ -57,6 +57,8 @@ int key_task_permission(const key_ref_t key_ref, | |||
57 | kperm = key->perm; | 57 | kperm = key->perm; |
58 | 58 | ||
59 | use_these_perms: | 59 | use_these_perms: |
60 | rcu_read_lock(); | ||
61 | |||
60 | /* use the top 8-bits of permissions for keys the caller possesses | 62 | /* use the top 8-bits of permissions for keys the caller possesses |
61 | * - possessor permissions are additive with other permissions | 63 | * - possessor permissions are additive with other permissions |
62 | */ | 64 | */ |
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, | |||
412 | struct task_struct *context) | 412 | struct task_struct *context) |
413 | { | 413 | { |
414 | struct request_key_auth *rka; | 414 | struct request_key_auth *rka; |
415 | struct cred *cred; | ||
415 | key_ref_t key_ref, ret, err; | 416 | key_ref_t key_ref, ret, err; |
416 | 417 | ||
417 | might_sleep(); | 418 | might_sleep(); |
418 | 419 | ||
420 | cred = get_task_cred(context); | ||
421 | |||
419 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 422 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
420 | * searchable, but we failed to find a key or we found a negative key; | 423 | * searchable, but we failed to find a key or we found a negative key; |
421 | * otherwise we want to return a sample error (probably -EACCES) if | 424 | * 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, | |||
428 | err = ERR_PTR(-EAGAIN); | 431 | err = ERR_PTR(-EAGAIN); |
429 | 432 | ||
430 | /* search the thread keyring first */ | 433 | /* search the thread keyring first */ |
431 | if (context->cred->thread_keyring) { | 434 | if (cred->thread_keyring) { |
432 | key_ref = keyring_search_aux( | 435 | key_ref = keyring_search_aux( |
433 | make_key_ref(context->cred->thread_keyring, 1), | 436 | make_key_ref(cred->thread_keyring, 1), |
434 | context, type, description, match); | 437 | context, type, description, match); |
435 | if (!IS_ERR(key_ref)) | 438 | if (!IS_ERR(key_ref)) |
436 | goto found; | 439 | goto found; |
@@ -495,9 +498,9 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
495 | } | 498 | } |
496 | } | 499 | } |
497 | /* or search the user-session keyring */ | 500 | /* or search the user-session keyring */ |
498 | else if (context->cred->user->session_keyring) { | 501 | else if (cred->user->session_keyring) { |
499 | key_ref = keyring_search_aux( | 502 | key_ref = keyring_search_aux( |
500 | make_key_ref(context->cred->user->session_keyring, 1), | 503 | make_key_ref(cred->user->session_keyring, 1), |
501 | context, type, description, match); | 504 | context, type, description, match); |
502 | if (!IS_ERR(key_ref)) | 505 | if (!IS_ERR(key_ref)) |
503 | goto found; | 506 | goto found; |
@@ -519,20 +522,20 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
519 | * search the keyrings of the process mentioned there | 522 | * search the keyrings of the process mentioned there |
520 | * - we don't permit access to request_key auth keys via this method | 523 | * - we don't permit access to request_key auth keys via this method |
521 | */ | 524 | */ |
522 | if (context->cred->request_key_auth && | 525 | if (cred->request_key_auth && |
523 | context == current && | 526 | context == current && |
524 | type != &key_type_request_key_auth | 527 | type != &key_type_request_key_auth |
525 | ) { | 528 | ) { |
526 | /* defend against the auth key being revoked */ | 529 | /* defend against the auth key being revoked */ |
527 | down_read(&context->cred->request_key_auth->sem); | 530 | down_read(&cred->request_key_auth->sem); |
528 | 531 | ||
529 | if (key_validate(context->cred->request_key_auth) == 0) { | 532 | if (key_validate(cred->request_key_auth) == 0) { |
530 | rka = context->cred->request_key_auth->payload.data; | 533 | rka = cred->request_key_auth->payload.data; |
531 | 534 | ||
532 | key_ref = search_process_keyrings(type, description, | 535 | key_ref = search_process_keyrings(type, description, |
533 | match, rka->context); | 536 | match, rka->context); |
534 | 537 | ||
535 | up_read(&context->cred->request_key_auth->sem); | 538 | up_read(&cred->request_key_auth->sem); |
536 | 539 | ||
537 | if (!IS_ERR(key_ref)) | 540 | if (!IS_ERR(key_ref)) |
538 | goto found; | 541 | goto found; |
@@ -549,7 +552,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
549 | break; | 552 | break; |
550 | } | 553 | } |
551 | } else { | 554 | } else { |
552 | up_read(&context->cred->request_key_auth->sem); | 555 | up_read(&cred->request_key_auth->sem); |
553 | } | 556 | } |
554 | } | 557 | } |
555 | 558 | ||
@@ -557,6 +560,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
557 | key_ref = ret ? ret : err; | 560 | key_ref = ret ? ret : err; |
558 | 561 | ||
559 | found: | 562 | found: |
563 | put_cred(cred); | ||
560 | return key_ref; | 564 | return key_ref; |
561 | 565 | ||
562 | } /* end search_process_keyrings() */ | 566 | } /* end search_process_keyrings() */ |