diff options
Diffstat (limited to 'security/keys/process_keys.c')
| -rw-r--r-- | security/keys/process_keys.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 276d27882ce8..5c23afb31ece 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/security.h> | ||
| 20 | #include <linux/user_namespace.h> | 21 | #include <linux/user_namespace.h> |
| 21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 22 | #include "internal.h" | 23 | #include "internal.h" |
| @@ -487,7 +488,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target) | |||
| 487 | * - don't create special keyrings unless so requested | 488 | * - don't create special keyrings unless so requested |
| 488 | * - partially constructed keys aren't found unless requested | 489 | * - partially constructed keys aren't found unless requested |
| 489 | */ | 490 | */ |
| 490 | key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 491 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, |
| 491 | key_perm_t perm) | 492 | key_perm_t perm) |
| 492 | { | 493 | { |
| 493 | struct request_key_auth *rka; | 494 | struct request_key_auth *rka; |
| @@ -503,7 +504,7 @@ try_again: | |||
| 503 | switch (id) { | 504 | switch (id) { |
| 504 | case KEY_SPEC_THREAD_KEYRING: | 505 | case KEY_SPEC_THREAD_KEYRING: |
| 505 | if (!cred->thread_keyring) { | 506 | if (!cred->thread_keyring) { |
| 506 | if (!create) | 507 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 507 | goto error; | 508 | goto error; |
| 508 | 509 | ||
| 509 | ret = install_thread_keyring(); | 510 | ret = install_thread_keyring(); |
| @@ -521,7 +522,7 @@ try_again: | |||
| 521 | 522 | ||
| 522 | case KEY_SPEC_PROCESS_KEYRING: | 523 | case KEY_SPEC_PROCESS_KEYRING: |
| 523 | if (!cred->tgcred->process_keyring) { | 524 | if (!cred->tgcred->process_keyring) { |
| 524 | if (!create) | 525 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 525 | goto error; | 526 | goto error; |
| 526 | 527 | ||
| 527 | ret = install_process_keyring(); | 528 | ret = install_process_keyring(); |
| @@ -642,7 +643,14 @@ try_again: | |||
| 642 | break; | 643 | break; |
| 643 | } | 644 | } |
| 644 | 645 | ||
| 645 | if (!partial) { | 646 | /* unlink does not use the nominated key in any way, so can skip all |
| 647 | * the permission checks as it is only concerned with the keyring */ | ||
| 648 | if (lflags & KEY_LOOKUP_FOR_UNLINK) { | ||
| 649 | ret = 0; | ||
| 650 | goto error; | ||
| 651 | } | ||
| 652 | |||
| 653 | if (!(lflags & KEY_LOOKUP_PARTIAL)) { | ||
| 646 | ret = wait_for_key_construction(key, true); | 654 | ret = wait_for_key_construction(key, true); |
| 647 | switch (ret) { | 655 | switch (ret) { |
| 648 | case -ERESTARTSYS: | 656 | case -ERESTARTSYS: |
| @@ -660,7 +668,8 @@ try_again: | |||
| 660 | } | 668 | } |
| 661 | 669 | ||
| 662 | ret = -EIO; | 670 | ret = -EIO; |
| 663 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 671 | if (!(lflags & KEY_LOOKUP_PARTIAL) && |
| 672 | !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | ||
| 664 | goto invalid_key; | 673 | goto invalid_key; |
| 665 | 674 | ||
| 666 | /* check the permissions */ | 675 | /* check the permissions */ |
| @@ -702,7 +711,7 @@ long join_session_keyring(const char *name) | |||
| 702 | /* only permit this if there's a single thread in the thread group - | 711 | /* only permit this if there's a single thread in the thread group - |
| 703 | * this avoids us having to adjust the creds on all threads and risking | 712 | * this avoids us having to adjust the creds on all threads and risking |
| 704 | * ENOMEM */ | 713 | * ENOMEM */ |
| 705 | if (!is_single_threaded(current)) | 714 | if (!current_is_single_threaded()) |
| 706 | return -EMLINK; | 715 | return -EMLINK; |
| 707 | 716 | ||
| 708 | new = prepare_creds(); | 717 | new = prepare_creds(); |
| @@ -760,3 +769,51 @@ error: | |||
| 760 | abort_creds(new); | 769 | abort_creds(new); |
| 761 | return ret; | 770 | return ret; |
| 762 | } | 771 | } |
| 772 | |||
| 773 | /* | ||
| 774 | * Replace a process's session keyring when that process resumes userspace on | ||
| 775 | * behalf of one of its children | ||
| 776 | */ | ||
| 777 | void key_replace_session_keyring(void) | ||
| 778 | { | ||
| 779 | const struct cred *old; | ||
| 780 | struct cred *new; | ||
| 781 | |||
| 782 | if (!current->replacement_session_keyring) | ||
| 783 | return; | ||
| 784 | |||
| 785 | write_lock_irq(&tasklist_lock); | ||
| 786 | new = current->replacement_session_keyring; | ||
| 787 | current->replacement_session_keyring = NULL; | ||
| 788 | write_unlock_irq(&tasklist_lock); | ||
| 789 | |||
| 790 | if (!new) | ||
| 791 | return; | ||
| 792 | |||
| 793 | old = current_cred(); | ||
| 794 | new-> uid = old-> uid; | ||
| 795 | new-> euid = old-> euid; | ||
| 796 | new-> suid = old-> suid; | ||
| 797 | new->fsuid = old->fsuid; | ||
| 798 | new-> gid = old-> gid; | ||
| 799 | new-> egid = old-> egid; | ||
| 800 | new-> sgid = old-> sgid; | ||
| 801 | new->fsgid = old->fsgid; | ||
| 802 | new->user = get_uid(old->user); | ||
| 803 | new->group_info = get_group_info(old->group_info); | ||
| 804 | |||
| 805 | new->securebits = old->securebits; | ||
| 806 | new->cap_inheritable = old->cap_inheritable; | ||
| 807 | new->cap_permitted = old->cap_permitted; | ||
| 808 | new->cap_effective = old->cap_effective; | ||
| 809 | new->cap_bset = old->cap_bset; | ||
| 810 | |||
| 811 | new->jit_keyring = old->jit_keyring; | ||
| 812 | new->thread_keyring = key_get(old->thread_keyring); | ||
| 813 | new->tgcred->tgid = old->tgcred->tgid; | ||
| 814 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
| 815 | |||
| 816 | security_transfer_creds(new, old); | ||
| 817 | |||
| 818 | commit_creds(new); | ||
| 819 | } | ||
