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 | } | ||