diff options
34 files changed, 409 insertions, 0 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 203487e9b1d8..e4dbbdb1bd96 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
| @@ -757,6 +757,26 @@ The keyctl syscall functions are: | |||
| 757 | successful. | 757 | successful. |
| 758 | 758 | ||
| 759 | 759 | ||
| 760 | (*) Install the calling process's session keyring on its parent. | ||
| 761 | |||
| 762 | long keyctl(KEYCTL_SESSION_TO_PARENT); | ||
| 763 | |||
| 764 | This functions attempts to install the calling process's session keyring | ||
| 765 | on to the calling process's parent, replacing the parent's current session | ||
| 766 | keyring. | ||
| 767 | |||
| 768 | The calling process must have the same ownership as its parent, the | ||
| 769 | keyring must have the same ownership as the calling process, the calling | ||
| 770 | process must have LINK permission on the keyring and the active LSM module | ||
| 771 | mustn't deny permission, otherwise error EPERM will be returned. | ||
| 772 | |||
| 773 | Error ENOMEM will be returned if there was insufficient memory to complete | ||
| 774 | the operation, otherwise 0 will be returned to indicate success. | ||
| 775 | |||
| 776 | The keyring will be replaced next time the parent process leaves the | ||
| 777 | kernel and resumes executing userspace. | ||
| 778 | |||
| 779 | |||
| 760 | =============== | 780 | =============== |
| 761 | KERNEL SERVICES | 781 | KERNEL SERVICES |
| 762 | =============== | 782 | =============== |
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 04e17c1f0f1b..d91aaa747050 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
| @@ -687,5 +687,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, | |||
| 687 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 687 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 688 | clear_thread_flag(TIF_NOTIFY_RESUME); | 688 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 689 | tracehook_notify_resume(regs); | 689 | tracehook_notify_resume(regs); |
| 690 | if (current->replacement_session_keyring) | ||
| 691 | key_replace_session_keyring(); | ||
| 690 | } | 692 | } |
| 691 | } | 693 | } |
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 13dec276927a..ea4ad3a43c88 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -711,5 +711,7 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) | |||
| 711 | if (thread_flags & _TIF_NOTIFY_RESUME) { | 711 | if (thread_flags & _TIF_NOTIFY_RESUME) { |
| 712 | clear_thread_flag(TIF_NOTIFY_RESUME); | 712 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 713 | tracehook_notify_resume(regs); | 713 | tracehook_notify_resume(regs); |
| 714 | if (current->replacement_session_keyring) | ||
| 715 | key_replace_session_keyring(); | ||
| 714 | } | 716 | } |
| 715 | } | 717 | } |
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 62d242e2d033..de9f7fe2aefa 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c | |||
| @@ -326,5 +326,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) | |||
| 326 | if (ti->flags & _TIF_NOTIFY_RESUME) { | 326 | if (ti->flags & _TIF_NOTIFY_RESUME) { |
| 327 | clear_thread_flag(TIF_NOTIFY_RESUME); | 327 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 328 | tracehook_notify_resume(regs); | 328 | tracehook_notify_resume(regs); |
| 329 | if (current->replacement_session_keyring) | ||
| 330 | key_replace_session_keyring(); | ||
| 329 | } | 331 | } |
| 330 | } | 332 | } |
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index 4f06d7fb43dd..32e9d5ee895b 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c | |||
| @@ -40,5 +40,7 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, | |||
| 40 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 40 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 41 | clear_thread_flag(TIF_NOTIFY_RESUME); | 41 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 42 | tracehook_notify_resume(regs); | 42 | tracehook_notify_resume(regs); |
| 43 | if (current->replacement_session_keyring) | ||
| 44 | key_replace_session_keyring(); | ||
| 43 | } | 45 | } |
| 44 | } | 46 | } |
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 4a7a62c6e783..6b0a2b6fed6a 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
| @@ -572,6 +572,8 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) | |||
| 572 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 572 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 573 | clear_thread_flag(TIF_NOTIFY_RESUME); | 573 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 574 | tracehook_notify_resume(__frame); | 574 | tracehook_notify_resume(__frame); |
| 575 | if (current->replacement_session_keyring) | ||
| 576 | key_replace_session_keyring(); | ||
| 575 | } | 577 | } |
| 576 | 578 | ||
| 577 | } /* end do_notify_resume() */ | 579 | } /* end do_notify_resume() */ |
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 56b3ab7dbbb0..abac3ee8c52a 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c | |||
| @@ -556,5 +556,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) | |||
| 556 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 556 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 557 | clear_thread_flag(TIF_NOTIFY_RESUME); | 557 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 558 | tracehook_notify_resume(regs); | 558 | tracehook_notify_resume(regs); |
| 559 | if (current->replacement_session_keyring) | ||
| 560 | key_replace_session_keyring(); | ||
| 559 | } | 561 | } |
| 560 | } | 562 | } |
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 5d7c0e5b9e76..89969e950045 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c | |||
| @@ -192,6 +192,8 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall) | |||
| 192 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { | 192 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { |
| 193 | clear_thread_flag(TIF_NOTIFY_RESUME); | 193 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 194 | tracehook_notify_resume(&scr->pt); | 194 | tracehook_notify_resume(&scr->pt); |
| 195 | if (current->replacement_session_keyring) | ||
| 196 | key_replace_session_keyring(); | ||
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | /* copy user rbs to kernel rbs */ | 199 | /* copy user rbs to kernel rbs */ |
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 3220258be188..f80bac17c65c 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c | |||
| @@ -411,6 +411,8 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | |||
| 411 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 411 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 412 | clear_thread_flag(TIF_NOTIFY_RESUME); | 412 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 413 | tracehook_notify_resume(regs); | 413 | tracehook_notify_resume(regs); |
| 414 | if (current->replacement_session_keyring) | ||
| 415 | key_replace_session_keyring(); | ||
| 414 | } | 416 | } |
| 415 | 417 | ||
| 416 | clear_thread_flag(TIF_IRET); | 418 | clear_thread_flag(TIF_IRET); |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index a3d1015471de..c2acf31874a4 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
| @@ -704,5 +704,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, | |||
| 704 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 704 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 705 | clear_thread_flag(TIF_NOTIFY_RESUME); | 705 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 706 | tracehook_notify_resume(regs); | 706 | tracehook_notify_resume(regs); |
| 707 | if (current->replacement_session_keyring) | ||
| 708 | key_replace_session_keyring(); | ||
| 707 | } | 709 | } |
| 708 | } | 710 | } |
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index feb2f2e810db..a21f43bc68e2 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c | |||
| @@ -568,5 +568,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) | |||
| 568 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 568 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 569 | clear_thread_flag(TIF_NOTIFY_RESUME); | 569 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 570 | tracehook_notify_resume(__frame); | 570 | tracehook_notify_resume(__frame); |
| 571 | if (current->replacement_session_keyring) | ||
| 572 | key_replace_session_keyring(); | ||
| 571 | } | 573 | } |
| 572 | } | 574 | } |
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index b3bfc4326703..5ca1c02b805a 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
| @@ -649,5 +649,7 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall) | |||
| 649 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { | 649 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { |
| 650 | clear_thread_flag(TIF_NOTIFY_RESUME); | 650 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 651 | tracehook_notify_resume(regs); | 651 | tracehook_notify_resume(regs); |
| 652 | if (current->replacement_session_keyring) | ||
| 653 | key_replace_session_keyring(); | ||
| 652 | } | 654 | } |
| 653 | } | 655 | } |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 062bd64e65fa..6b4fef877f9d 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
| @@ -536,4 +536,6 @@ void do_notify_resume(struct pt_regs *regs) | |||
| 536 | { | 536 | { |
| 537 | clear_thread_flag(TIF_NOTIFY_RESUME); | 537 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 538 | tracehook_notify_resume(regs); | 538 | tracehook_notify_resume(regs); |
| 539 | if (current->replacement_session_keyring) | ||
| 540 | key_replace_session_keyring(); | ||
| 539 | } | 541 | } |
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index b5afbec1db59..04a21883f327 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
| @@ -640,5 +640,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, | |||
| 640 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 640 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 641 | clear_thread_flag(TIF_NOTIFY_RESUME); | 641 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 642 | tracehook_notify_resume(regs); | 642 | tracehook_notify_resume(regs); |
| 643 | if (current->replacement_session_keyring) | ||
| 644 | key_replace_session_keyring(); | ||
| 643 | } | 645 | } |
| 644 | } | 646 | } |
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 0663a0ee6021..9e5c9b1d7e98 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
| @@ -772,5 +772,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info | |||
| 772 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 772 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 773 | clear_thread_flag(TIF_NOTIFY_RESUME); | 773 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 774 | tracehook_notify_resume(regs); | 774 | tracehook_notify_resume(regs); |
| 775 | if (current->replacement_session_keyring) | ||
| 776 | key_replace_session_keyring(); | ||
| 775 | } | 777 | } |
| 776 | } | 778 | } |
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 181d069a2d44..7ce1a1005b1d 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c | |||
| @@ -590,6 +590,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, | |||
| 590 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 590 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 591 | clear_thread_flag(TIF_NOTIFY_RESUME); | 591 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 592 | tracehook_notify_resume(regs); | 592 | tracehook_notify_resume(regs); |
| 593 | if (current->replacement_session_keyring) | ||
| 594 | key_replace_session_keyring(); | ||
| 593 | } | 595 | } |
| 594 | } | 596 | } |
| 595 | 597 | ||
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index ec82d76dc6f2..647afbda7ae1 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c | |||
| @@ -613,5 +613,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long | |||
| 613 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 613 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 614 | clear_thread_flag(TIF_NOTIFY_RESUME); | 614 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 615 | tracehook_notify_resume(regs); | 615 | tracehook_notify_resume(regs); |
| 616 | if (current->replacement_session_keyring) | ||
| 617 | key_replace_session_keyring(); | ||
| 616 | } | 618 | } |
| 617 | } | 619 | } |
| 620 | |||
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4c578751e94e..81e58238c4ce 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
| @@ -869,6 +869,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
| 869 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 869 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 870 | clear_thread_flag(TIF_NOTIFY_RESUME); | 870 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 871 | tracehook_notify_resume(regs); | 871 | tracehook_notify_resume(regs); |
| 872 | if (current->replacement_session_keyring) | ||
| 873 | key_replace_session_keyring(); | ||
| 872 | } | 874 | } |
| 873 | 875 | ||
| 874 | #ifdef CONFIG_X86_32 | 876 | #ifdef CONFIG_X86_32 |
diff --git a/include/linux/cred.h b/include/linux/cred.h index 85439abdbc80..24520a539c6f 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
| @@ -152,6 +152,7 @@ struct cred { | |||
| 152 | extern void __put_cred(struct cred *); | 152 | extern void __put_cred(struct cred *); |
| 153 | extern void exit_creds(struct task_struct *); | 153 | extern void exit_creds(struct task_struct *); |
| 154 | extern int copy_creds(struct task_struct *, unsigned long); | 154 | extern int copy_creds(struct task_struct *, unsigned long); |
| 155 | extern struct cred *cred_alloc_blank(void); | ||
| 155 | extern struct cred *prepare_creds(void); | 156 | extern struct cred *prepare_creds(void); |
| 156 | extern struct cred *prepare_exec_creds(void); | 157 | extern struct cred *prepare_exec_creds(void); |
| 157 | extern struct cred *prepare_usermodehelper_creds(void); | 158 | extern struct cred *prepare_usermodehelper_creds(void); |
diff --git a/include/linux/key.h b/include/linux/key.h index 33e0165de100..cd50dfa1d4c2 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -278,6 +278,8 @@ static inline key_serial_t key_serial(struct key *key) | |||
| 278 | extern ctl_table key_sysctls[]; | 278 | extern ctl_table key_sysctls[]; |
| 279 | #endif | 279 | #endif |
| 280 | 280 | ||
| 281 | extern void key_replace_session_keyring(void); | ||
| 282 | |||
| 281 | /* | 283 | /* |
| 282 | * the userspace interface | 284 | * the userspace interface |
| 283 | */ | 285 | */ |
| @@ -300,6 +302,7 @@ extern void key_init(void); | |||
| 300 | #define key_fsuid_changed(t) do { } while(0) | 302 | #define key_fsuid_changed(t) do { } while(0) |
| 301 | #define key_fsgid_changed(t) do { } while(0) | 303 | #define key_fsgid_changed(t) do { } while(0) |
| 302 | #define key_init() do { } while(0) | 304 | #define key_init() do { } while(0) |
| 305 | #define key_replace_session_keyring() do { } while(0) | ||
| 303 | 306 | ||
| 304 | #endif /* CONFIG_KEYS */ | 307 | #endif /* CONFIG_KEYS */ |
| 305 | #endif /* __KERNEL__ */ | 308 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index c0688eb72093..bd383f1944fb 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h | |||
| @@ -52,5 +52,6 @@ | |||
| 52 | #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ | 52 | #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ |
| 53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ | 53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ |
| 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ | 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ |
| 55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ | ||
| 55 | 56 | ||
| 56 | #endif /* _LINUX_KEYCTL_H */ | 57 | #endif /* _LINUX_KEYCTL_H */ |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 5c7ce13c1696..9304027673b0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1292,6 +1292,7 @@ struct task_struct { | |||
| 1292 | struct mutex cred_guard_mutex; /* guard against foreign influences on | 1292 | struct mutex cred_guard_mutex; /* guard against foreign influences on |
| 1293 | * credential calculations | 1293 | * credential calculations |
| 1294 | * (notably. ptrace) */ | 1294 | * (notably. ptrace) */ |
| 1295 | struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */ | ||
| 1295 | 1296 | ||
| 1296 | char comm[TASK_COMM_LEN]; /* executable name excluding path | 1297 | char comm[TASK_COMM_LEN]; /* executable name excluding path |
| 1297 | - access with [gs]et_task_comm (which lock | 1298 | - access with [gs]et_task_comm (which lock |
diff --git a/include/linux/security.h b/include/linux/security.h index 40ba39ea68ce..97de3fe3dd0d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -653,6 +653,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 653 | * manual page for definitions of the @clone_flags. | 653 | * manual page for definitions of the @clone_flags. |
| 654 | * @clone_flags contains the flags indicating what should be shared. | 654 | * @clone_flags contains the flags indicating what should be shared. |
| 655 | * Return 0 if permission is granted. | 655 | * Return 0 if permission is granted. |
| 656 | * @cred_alloc_blank: | ||
| 657 | * @cred points to the credentials. | ||
| 658 | * @gfp indicates the atomicity of any memory allocations. | ||
| 659 | * Only allocate sufficient memory and attach to @cred such that | ||
| 660 | * cred_transfer() will not get ENOMEM. | ||
| 656 | * @cred_free: | 661 | * @cred_free: |
| 657 | * @cred points to the credentials. | 662 | * @cred points to the credentials. |
| 658 | * Deallocate and clear the cred->security field in a set of credentials. | 663 | * Deallocate and clear the cred->security field in a set of credentials. |
| @@ -665,6 +670,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 665 | * @new points to the new credentials. | 670 | * @new points to the new credentials. |
| 666 | * @old points to the original credentials. | 671 | * @old points to the original credentials. |
| 667 | * Install a new set of credentials. | 672 | * Install a new set of credentials. |
| 673 | * @cred_transfer: | ||
| 674 | * @new points to the new credentials. | ||
| 675 | * @old points to the original credentials. | ||
| 676 | * Transfer data from original creds to new creds | ||
| 668 | * @kernel_act_as: | 677 | * @kernel_act_as: |
| 669 | * Set the credentials for a kernel service to act as (subjective context). | 678 | * Set the credentials for a kernel service to act as (subjective context). |
| 670 | * @new points to the credentials to be modified. | 679 | * @new points to the credentials to be modified. |
| @@ -1103,6 +1112,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 1103 | * Return the length of the string (including terminating NUL) or -ve if | 1112 | * Return the length of the string (including terminating NUL) or -ve if |
| 1104 | * an error. | 1113 | * an error. |
| 1105 | * May also return 0 (and a NULL buffer pointer) if there is no label. | 1114 | * May also return 0 (and a NULL buffer pointer) if there is no label. |
| 1115 | * @key_session_to_parent: | ||
| 1116 | * Forcibly assign the session keyring from a process to its parent | ||
| 1117 | * process. | ||
| 1118 | * @cred: Pointer to process's credentials | ||
| 1119 | * @parent_cred: Pointer to parent process's credentials | ||
| 1120 | * @keyring: Proposed new session keyring | ||
| 1121 | * Return 0 if permission is granted, -ve error otherwise. | ||
| 1106 | * | 1122 | * |
| 1107 | * Security hooks affecting all System V IPC operations. | 1123 | * Security hooks affecting all System V IPC operations. |
| 1108 | * | 1124 | * |
| @@ -1498,10 +1514,12 @@ struct security_operations { | |||
| 1498 | int (*dentry_open) (struct file *file, const struct cred *cred); | 1514 | int (*dentry_open) (struct file *file, const struct cred *cred); |
| 1499 | 1515 | ||
| 1500 | int (*task_create) (unsigned long clone_flags); | 1516 | int (*task_create) (unsigned long clone_flags); |
| 1517 | int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp); | ||
| 1501 | void (*cred_free) (struct cred *cred); | 1518 | void (*cred_free) (struct cred *cred); |
| 1502 | int (*cred_prepare)(struct cred *new, const struct cred *old, | 1519 | int (*cred_prepare)(struct cred *new, const struct cred *old, |
| 1503 | gfp_t gfp); | 1520 | gfp_t gfp); |
| 1504 | void (*cred_commit)(struct cred *new, const struct cred *old); | 1521 | void (*cred_commit)(struct cred *new, const struct cred *old); |
| 1522 | void (*cred_transfer)(struct cred *new, const struct cred *old); | ||
| 1505 | int (*kernel_act_as)(struct cred *new, u32 secid); | 1523 | int (*kernel_act_as)(struct cred *new, u32 secid); |
| 1506 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); | 1524 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); |
| 1507 | int (*kernel_module_request)(void); | 1525 | int (*kernel_module_request)(void); |
| @@ -1639,6 +1657,9 @@ struct security_operations { | |||
| 1639 | const struct cred *cred, | 1657 | const struct cred *cred, |
| 1640 | key_perm_t perm); | 1658 | key_perm_t perm); |
| 1641 | int (*key_getsecurity)(struct key *key, char **_buffer); | 1659 | int (*key_getsecurity)(struct key *key, char **_buffer); |
| 1660 | int (*key_session_to_parent)(const struct cred *cred, | ||
| 1661 | const struct cred *parent_cred, | ||
| 1662 | struct key *key); | ||
| 1642 | #endif /* CONFIG_KEYS */ | 1663 | #endif /* CONFIG_KEYS */ |
| 1643 | 1664 | ||
| 1644 | #ifdef CONFIG_AUDIT | 1665 | #ifdef CONFIG_AUDIT |
| @@ -1755,9 +1776,11 @@ int security_file_send_sigiotask(struct task_struct *tsk, | |||
| 1755 | int security_file_receive(struct file *file); | 1776 | int security_file_receive(struct file *file); |
| 1756 | int security_dentry_open(struct file *file, const struct cred *cred); | 1777 | int security_dentry_open(struct file *file, const struct cred *cred); |
| 1757 | int security_task_create(unsigned long clone_flags); | 1778 | int security_task_create(unsigned long clone_flags); |
| 1779 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); | ||
| 1758 | void security_cred_free(struct cred *cred); | 1780 | void security_cred_free(struct cred *cred); |
| 1759 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); | 1781 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); |
| 1760 | void security_commit_creds(struct cred *new, const struct cred *old); | 1782 | void security_commit_creds(struct cred *new, const struct cred *old); |
| 1783 | void security_transfer_creds(struct cred *new, const struct cred *old); | ||
| 1761 | int security_kernel_act_as(struct cred *new, u32 secid); | 1784 | int security_kernel_act_as(struct cred *new, u32 secid); |
| 1762 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); | 1785 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); |
| 1763 | int security_kernel_module_request(void); | 1786 | int security_kernel_module_request(void); |
| @@ -2286,6 +2309,9 @@ static inline int security_task_create(unsigned long clone_flags) | |||
| 2286 | return 0; | 2309 | return 0; |
| 2287 | } | 2310 | } |
| 2288 | 2311 | ||
| 2312 | static inline void security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 2313 | { } | ||
| 2314 | |||
| 2289 | static inline void security_cred_free(struct cred *cred) | 2315 | static inline void security_cred_free(struct cred *cred) |
| 2290 | { } | 2316 | { } |
| 2291 | 2317 | ||
| @@ -2301,6 +2327,11 @@ static inline void security_commit_creds(struct cred *new, | |||
| 2301 | { | 2327 | { |
| 2302 | } | 2328 | } |
| 2303 | 2329 | ||
| 2330 | static inline void security_transfer_creds(struct cred *new, | ||
| 2331 | const struct cred *old) | ||
| 2332 | { | ||
| 2333 | } | ||
| 2334 | |||
| 2304 | static inline int security_kernel_act_as(struct cred *cred, u32 secid) | 2335 | static inline int security_kernel_act_as(struct cred *cred, u32 secid) |
| 2305 | { | 2336 | { |
| 2306 | return 0; | 2337 | return 0; |
| @@ -2923,6 +2954,9 @@ void security_key_free(struct key *key); | |||
| 2923 | int security_key_permission(key_ref_t key_ref, | 2954 | int security_key_permission(key_ref_t key_ref, |
| 2924 | const struct cred *cred, key_perm_t perm); | 2955 | const struct cred *cred, key_perm_t perm); |
| 2925 | int security_key_getsecurity(struct key *key, char **_buffer); | 2956 | int security_key_getsecurity(struct key *key, char **_buffer); |
| 2957 | int security_key_session_to_parent(const struct cred *cred, | ||
| 2958 | const struct cred *parent_cred, | ||
| 2959 | struct key *key); | ||
| 2926 | 2960 | ||
| 2927 | #else | 2961 | #else |
| 2928 | 2962 | ||
| @@ -2950,6 +2984,10 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer) | |||
| 2950 | return 0; | 2984 | return 0; |
| 2951 | } | 2985 | } |
| 2952 | 2986 | ||
| 2987 | static inline int security_key_session_to_parent(const struct cred *cred, | ||
| 2988 | const struct cred *parent_cred, | ||
| 2989 | struct key *key); | ||
| 2990 | |||
| 2953 | #endif | 2991 | #endif |
| 2954 | #endif /* CONFIG_KEYS */ | 2992 | #endif /* CONFIG_KEYS */ |
| 2955 | 2993 | ||
diff --git a/kernel/cred.c b/kernel/cred.c index 24dd2f5104b1..006fcab009d5 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -199,6 +199,49 @@ void exit_creds(struct task_struct *tsk) | |||
| 199 | validate_creds(cred); | 199 | validate_creds(cred); |
| 200 | alter_cred_subscribers(cred, -1); | 200 | alter_cred_subscribers(cred, -1); |
| 201 | put_cred(cred); | 201 | put_cred(cred); |
| 202 | |||
| 203 | cred = (struct cred *) tsk->replacement_session_keyring; | ||
| 204 | if (cred) { | ||
| 205 | tsk->replacement_session_keyring = NULL; | ||
| 206 | validate_creds(cred); | ||
| 207 | put_cred(cred); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Allocate blank credentials, such that the credentials can be filled in at a | ||
| 213 | * later date without risk of ENOMEM. | ||
| 214 | */ | ||
| 215 | struct cred *cred_alloc_blank(void) | ||
| 216 | { | ||
| 217 | struct cred *new; | ||
| 218 | |||
| 219 | new = kmem_cache_zalloc(cred_jar, GFP_KERNEL); | ||
| 220 | if (!new) | ||
| 221 | return NULL; | ||
| 222 | |||
| 223 | #ifdef CONFIG_KEYS | ||
| 224 | new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); | ||
| 225 | if (!new->tgcred) { | ||
| 226 | kfree(new); | ||
| 227 | return NULL; | ||
| 228 | } | ||
| 229 | atomic_set(&new->tgcred->usage, 1); | ||
| 230 | #endif | ||
| 231 | |||
| 232 | atomic_set(&new->usage, 1); | ||
| 233 | |||
| 234 | if (security_cred_alloc_blank(new, GFP_KERNEL) < 0) | ||
| 235 | goto error; | ||
| 236 | |||
| 237 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 238 | new->magic = CRED_MAGIC; | ||
| 239 | #endif | ||
| 240 | return new; | ||
| 241 | |||
| 242 | error: | ||
| 243 | abort_creds(new); | ||
| 244 | return NULL; | ||
| 202 | } | 245 | } |
| 203 | 246 | ||
| 204 | /** | 247 | /** |
diff --git a/security/capability.c b/security/capability.c index 06400cf07757..93a2ffe65905 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -373,6 +373,11 @@ static int cap_task_create(unsigned long clone_flags) | |||
| 373 | return 0; | 373 | return 0; |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 377 | { | ||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 376 | static void cap_cred_free(struct cred *cred) | 381 | static void cap_cred_free(struct cred *cred) |
| 377 | { | 382 | { |
| 378 | } | 383 | } |
| @@ -386,6 +391,10 @@ static void cap_cred_commit(struct cred *new, const struct cred *old) | |||
| 386 | { | 391 | { |
| 387 | } | 392 | } |
| 388 | 393 | ||
| 394 | static void cap_cred_transfer(struct cred *new, const struct cred *old) | ||
| 395 | { | ||
| 396 | } | ||
| 397 | |||
| 389 | static int cap_kernel_act_as(struct cred *new, u32 secid) | 398 | static int cap_kernel_act_as(struct cred *new, u32 secid) |
| 390 | { | 399 | { |
| 391 | return 0; | 400 | return 0; |
| @@ -836,6 +845,13 @@ static int cap_key_getsecurity(struct key *key, char **_buffer) | |||
| 836 | return 0; | 845 | return 0; |
| 837 | } | 846 | } |
| 838 | 847 | ||
| 848 | static int cap_key_session_to_parent(const struct cred *cred, | ||
| 849 | const struct cred *parent_cred, | ||
| 850 | struct key *key) | ||
| 851 | { | ||
| 852 | return 0; | ||
| 853 | } | ||
| 854 | |||
| 839 | #endif /* CONFIG_KEYS */ | 855 | #endif /* CONFIG_KEYS */ |
| 840 | 856 | ||
| 841 | #ifdef CONFIG_AUDIT | 857 | #ifdef CONFIG_AUDIT |
| @@ -961,9 +977,11 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 961 | set_to_cap_if_null(ops, file_receive); | 977 | set_to_cap_if_null(ops, file_receive); |
| 962 | set_to_cap_if_null(ops, dentry_open); | 978 | set_to_cap_if_null(ops, dentry_open); |
| 963 | set_to_cap_if_null(ops, task_create); | 979 | set_to_cap_if_null(ops, task_create); |
| 980 | set_to_cap_if_null(ops, cred_alloc_blank); | ||
| 964 | set_to_cap_if_null(ops, cred_free); | 981 | set_to_cap_if_null(ops, cred_free); |
| 965 | set_to_cap_if_null(ops, cred_prepare); | 982 | set_to_cap_if_null(ops, cred_prepare); |
| 966 | set_to_cap_if_null(ops, cred_commit); | 983 | set_to_cap_if_null(ops, cred_commit); |
| 984 | set_to_cap_if_null(ops, cred_transfer); | ||
| 967 | set_to_cap_if_null(ops, kernel_act_as); | 985 | set_to_cap_if_null(ops, kernel_act_as); |
| 968 | set_to_cap_if_null(ops, kernel_create_files_as); | 986 | set_to_cap_if_null(ops, kernel_create_files_as); |
| 969 | set_to_cap_if_null(ops, kernel_module_request); | 987 | set_to_cap_if_null(ops, kernel_module_request); |
| @@ -1063,6 +1081,7 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1063 | set_to_cap_if_null(ops, key_free); | 1081 | set_to_cap_if_null(ops, key_free); |
| 1064 | set_to_cap_if_null(ops, key_permission); | 1082 | set_to_cap_if_null(ops, key_permission); |
| 1065 | set_to_cap_if_null(ops, key_getsecurity); | 1083 | set_to_cap_if_null(ops, key_getsecurity); |
| 1084 | set_to_cap_if_null(ops, key_session_to_parent); | ||
| 1066 | #endif /* CONFIG_KEYS */ | 1085 | #endif /* CONFIG_KEYS */ |
| 1067 | #ifdef CONFIG_AUDIT | 1086 | #ifdef CONFIG_AUDIT |
| 1068 | set_to_cap_if_null(ops, audit_rule_init); | 1087 | set_to_cap_if_null(ops, audit_rule_init); |
diff --git a/security/keys/compat.c b/security/keys/compat.c index c766c68a63bc..792c0a611a6d 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
| @@ -82,6 +82,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
| 82 | case KEYCTL_GET_SECURITY: | 82 | case KEYCTL_GET_SECURITY: |
| 83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); | 83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); |
| 84 | 84 | ||
| 85 | case KEYCTL_SESSION_TO_PARENT: | ||
| 86 | return keyctl_session_to_parent(); | ||
| 87 | |||
| 85 | default: | 88 | default: |
| 86 | return -EOPNOTSUPP; | 89 | return -EOPNOTSUPP; |
| 87 | } | 90 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c index 44adc325e15c..1e616aef55fd 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
| @@ -65,6 +65,7 @@ static void key_gc_timer_func(unsigned long data) | |||
| 65 | * - return true if we altered the keyring | 65 | * - return true if we altered the keyring |
| 66 | */ | 66 | */ |
| 67 | static bool key_gc_keyring(struct key *keyring, time_t limit) | 67 | static bool key_gc_keyring(struct key *keyring, time_t limit) |
| 68 | __releases(key_serial_lock) | ||
| 68 | { | 69 | { |
| 69 | struct keyring_list *klist; | 70 | struct keyring_list *klist; |
| 70 | struct key *key; | 71 | struct key *key; |
diff --git a/security/keys/internal.h b/security/keys/internal.h index fb830514c337..24ba0307b7ad 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -201,6 +201,7 @@ extern long keyctl_set_timeout(key_serial_t, unsigned); | |||
| 201 | extern long keyctl_assume_authority(key_serial_t); | 201 | extern long keyctl_assume_authority(key_serial_t); |
| 202 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | 202 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, |
| 203 | size_t buflen); | 203 | size_t buflen); |
| 204 | extern long keyctl_session_to_parent(void); | ||
| 204 | 205 | ||
| 205 | /* | 206 | /* |
| 206 | * debugging key validation | 207 | * debugging key validation |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 736d7800f97f..74c968524592 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -1228,6 +1228,105 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1228 | return ret; | 1228 | return ret; |
| 1229 | } | 1229 | } |
| 1230 | 1230 | ||
| 1231 | /* | ||
| 1232 | * attempt to install the calling process's session keyring on the process's | ||
| 1233 | * parent process | ||
| 1234 | * - the keyring must exist and must grant us LINK permission | ||
| 1235 | * - implements keyctl(KEYCTL_SESSION_TO_PARENT) | ||
| 1236 | */ | ||
| 1237 | long keyctl_session_to_parent(void) | ||
| 1238 | { | ||
| 1239 | struct task_struct *me, *parent; | ||
| 1240 | const struct cred *mycred, *pcred; | ||
| 1241 | struct cred *cred, *oldcred; | ||
| 1242 | key_ref_t keyring_r; | ||
| 1243 | int ret; | ||
| 1244 | |||
| 1245 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); | ||
| 1246 | if (IS_ERR(keyring_r)) | ||
| 1247 | return PTR_ERR(keyring_r); | ||
| 1248 | |||
| 1249 | /* our parent is going to need a new cred struct, a new tgcred struct | ||
| 1250 | * and new security data, so we allocate them here to prevent ENOMEM in | ||
| 1251 | * our parent */ | ||
| 1252 | ret = -ENOMEM; | ||
| 1253 | cred = cred_alloc_blank(); | ||
| 1254 | if (!cred) | ||
| 1255 | goto error_keyring; | ||
| 1256 | |||
| 1257 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | ||
| 1258 | keyring_r = NULL; | ||
| 1259 | |||
| 1260 | me = current; | ||
| 1261 | write_lock_irq(&tasklist_lock); | ||
| 1262 | |||
| 1263 | parent = me->real_parent; | ||
| 1264 | ret = -EPERM; | ||
| 1265 | |||
| 1266 | /* the parent mustn't be init and mustn't be a kernel thread */ | ||
| 1267 | if (parent->pid <= 1 || !parent->mm) | ||
| 1268 | goto not_permitted; | ||
| 1269 | |||
| 1270 | /* the parent must be single threaded */ | ||
| 1271 | if (atomic_read(&parent->signal->count) != 1) | ||
| 1272 | goto not_permitted; | ||
| 1273 | |||
| 1274 | /* the parent and the child must have different session keyrings or | ||
| 1275 | * there's no point */ | ||
| 1276 | mycred = current_cred(); | ||
| 1277 | pcred = __task_cred(parent); | ||
| 1278 | if (mycred == pcred || | ||
| 1279 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) | ||
| 1280 | goto already_same; | ||
| 1281 | |||
| 1282 | /* the parent must have the same effective ownership and mustn't be | ||
| 1283 | * SUID/SGID */ | ||
| 1284 | if (pcred-> uid != mycred->euid || | ||
| 1285 | pcred->euid != mycred->euid || | ||
| 1286 | pcred->suid != mycred->euid || | ||
| 1287 | pcred-> gid != mycred->egid || | ||
| 1288 | pcred->egid != mycred->egid || | ||
| 1289 | pcred->sgid != mycred->egid) | ||
| 1290 | goto not_permitted; | ||
| 1291 | |||
| 1292 | /* the keyrings must have the same UID */ | ||
| 1293 | if (pcred ->tgcred->session_keyring->uid != mycred->euid || | ||
| 1294 | mycred->tgcred->session_keyring->uid != mycred->euid) | ||
| 1295 | goto not_permitted; | ||
| 1296 | |||
| 1297 | /* the LSM must permit the replacement of the parent's keyring with the | ||
| 1298 | * keyring from this process */ | ||
| 1299 | ret = security_key_session_to_parent(mycred, pcred, | ||
| 1300 | key_ref_to_ptr(keyring_r)); | ||
| 1301 | if (ret < 0) | ||
| 1302 | goto not_permitted; | ||
| 1303 | |||
| 1304 | /* if there's an already pending keyring replacement, then we replace | ||
| 1305 | * that */ | ||
| 1306 | oldcred = parent->replacement_session_keyring; | ||
| 1307 | |||
| 1308 | /* the replacement session keyring is applied just prior to userspace | ||
| 1309 | * restarting */ | ||
| 1310 | parent->replacement_session_keyring = cred; | ||
| 1311 | cred = NULL; | ||
| 1312 | set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); | ||
| 1313 | |||
| 1314 | write_unlock_irq(&tasklist_lock); | ||
| 1315 | if (oldcred) | ||
| 1316 | put_cred(oldcred); | ||
| 1317 | return 0; | ||
| 1318 | |||
| 1319 | already_same: | ||
| 1320 | ret = 0; | ||
| 1321 | not_permitted: | ||
| 1322 | put_cred(cred); | ||
| 1323 | return ret; | ||
| 1324 | |||
| 1325 | error_keyring: | ||
| 1326 | key_ref_put(keyring_r); | ||
| 1327 | return ret; | ||
| 1328 | } | ||
| 1329 | |||
| 1231 | /*****************************************************************************/ | 1330 | /*****************************************************************************/ |
| 1232 | /* | 1331 | /* |
| 1233 | * the key control system call | 1332 | * the key control system call |
| @@ -1313,6 +1412,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1313 | (char __user *) arg3, | 1412 | (char __user *) arg3, |
| 1314 | (size_t) arg4); | 1413 | (size_t) arg4); |
| 1315 | 1414 | ||
| 1415 | case KEYCTL_SESSION_TO_PARENT: | ||
| 1416 | return keyctl_session_to_parent(); | ||
| 1417 | |||
| 1316 | default: | 1418 | default: |
| 1317 | return -EOPNOTSUPP; | 1419 | return -EOPNOTSUPP; |
| 1318 | } | 1420 | } |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 4739cfbb41b7..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" |
| @@ -768,3 +769,51 @@ error: | |||
| 768 | abort_creds(new); | 769 | abort_creds(new); |
| 769 | return ret; | 770 | return ret; |
| 770 | } | 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 | } | ||
diff --git a/security/security.c b/security/security.c index f88eaf6b14cc..d8b727637f02 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -684,6 +684,11 @@ int security_task_create(unsigned long clone_flags) | |||
| 684 | return security_ops->task_create(clone_flags); | 684 | return security_ops->task_create(clone_flags); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 688 | { | ||
| 689 | return security_ops->cred_alloc_blank(cred, gfp); | ||
| 690 | } | ||
| 691 | |||
| 687 | void security_cred_free(struct cred *cred) | 692 | void security_cred_free(struct cred *cred) |
| 688 | { | 693 | { |
| 689 | security_ops->cred_free(cred); | 694 | security_ops->cred_free(cred); |
| @@ -699,6 +704,11 @@ void security_commit_creds(struct cred *new, const struct cred *old) | |||
| 699 | security_ops->cred_commit(new, old); | 704 | security_ops->cred_commit(new, old); |
| 700 | } | 705 | } |
| 701 | 706 | ||
| 707 | void security_transfer_creds(struct cred *new, const struct cred *old) | ||
| 708 | { | ||
| 709 | security_ops->cred_transfer(new, old); | ||
| 710 | } | ||
| 711 | |||
| 702 | int security_kernel_act_as(struct cred *new, u32 secid) | 712 | int security_kernel_act_as(struct cred *new, u32 secid) |
| 703 | { | 713 | { |
| 704 | return security_ops->kernel_act_as(new, secid); | 714 | return security_ops->kernel_act_as(new, secid); |
| @@ -1241,6 +1251,13 @@ int security_key_getsecurity(struct key *key, char **_buffer) | |||
| 1241 | return security_ops->key_getsecurity(key, _buffer); | 1251 | return security_ops->key_getsecurity(key, _buffer); |
| 1242 | } | 1252 | } |
| 1243 | 1253 | ||
| 1254 | int security_key_session_to_parent(const struct cred *cred, | ||
| 1255 | const struct cred *parent_cred, | ||
| 1256 | struct key *key) | ||
| 1257 | { | ||
| 1258 | return security_ops->key_session_to_parent(cred, parent_cred, key); | ||
| 1259 | } | ||
| 1260 | |||
| 1244 | #endif /* CONFIG_KEYS */ | 1261 | #endif /* CONFIG_KEYS */ |
| 1245 | 1262 | ||
| 1246 | #ifdef CONFIG_AUDIT | 1263 | #ifdef CONFIG_AUDIT |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c3bb31ecc5aa..134a9c0d2004 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -3233,6 +3233,21 @@ static int selinux_task_create(unsigned long clone_flags) | |||
| 3233 | } | 3233 | } |
| 3234 | 3234 | ||
| 3235 | /* | 3235 | /* |
| 3236 | * allocate the SELinux part of blank credentials | ||
| 3237 | */ | ||
| 3238 | static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 3239 | { | ||
| 3240 | struct task_security_struct *tsec; | ||
| 3241 | |||
| 3242 | tsec = kzalloc(sizeof(struct task_security_struct), gfp); | ||
| 3243 | if (!tsec) | ||
| 3244 | return -ENOMEM; | ||
| 3245 | |||
| 3246 | cred->security = tsec; | ||
| 3247 | return 0; | ||
| 3248 | } | ||
| 3249 | |||
| 3250 | /* | ||
| 3236 | * detach and free the LSM part of a set of credentials | 3251 | * detach and free the LSM part of a set of credentials |
| 3237 | */ | 3252 | */ |
| 3238 | static void selinux_cred_free(struct cred *cred) | 3253 | static void selinux_cred_free(struct cred *cred) |
| @@ -3264,6 +3279,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, | |||
| 3264 | } | 3279 | } |
| 3265 | 3280 | ||
| 3266 | /* | 3281 | /* |
| 3282 | * transfer the SELinux data to a blank set of creds | ||
| 3283 | */ | ||
| 3284 | static void selinux_cred_transfer(struct cred *new, const struct cred *old) | ||
| 3285 | { | ||
| 3286 | const struct task_security_struct *old_tsec = old->security; | ||
| 3287 | struct task_security_struct *tsec = new->security; | ||
| 3288 | |||
| 3289 | *tsec = *old_tsec; | ||
| 3290 | } | ||
| 3291 | |||
| 3292 | /* | ||
| 3267 | * set the security data for a kernel service | 3293 | * set the security data for a kernel service |
| 3268 | * - all the creation contexts are set to unlabelled | 3294 | * - all the creation contexts are set to unlabelled |
| 3269 | */ | 3295 | */ |
| @@ -5469,8 +5495,10 @@ static struct security_operations selinux_ops = { | |||
| 5469 | .dentry_open = selinux_dentry_open, | 5495 | .dentry_open = selinux_dentry_open, |
| 5470 | 5496 | ||
| 5471 | .task_create = selinux_task_create, | 5497 | .task_create = selinux_task_create, |
| 5498 | .cred_alloc_blank = selinux_cred_alloc_blank, | ||
| 5472 | .cred_free = selinux_cred_free, | 5499 | .cred_free = selinux_cred_free, |
| 5473 | .cred_prepare = selinux_cred_prepare, | 5500 | .cred_prepare = selinux_cred_prepare, |
| 5501 | .cred_transfer = selinux_cred_transfer, | ||
| 5474 | .kernel_act_as = selinux_kernel_act_as, | 5502 | .kernel_act_as = selinux_kernel_act_as, |
| 5475 | .kernel_create_files_as = selinux_kernel_create_files_as, | 5503 | .kernel_create_files_as = selinux_kernel_create_files_as, |
| 5476 | .kernel_module_request = selinux_kernel_module_request, | 5504 | .kernel_module_request = selinux_kernel_module_request, |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c243a2b25832..969f5fee1906 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -1080,6 +1080,22 @@ static int smack_file_receive(struct file *file) | |||
| 1080 | */ | 1080 | */ |
| 1081 | 1081 | ||
| 1082 | /** | 1082 | /** |
| 1083 | * smack_cred_alloc_blank - "allocate" blank task-level security credentials | ||
| 1084 | * @new: the new credentials | ||
| 1085 | * @gfp: the atomicity of any memory allocations | ||
| 1086 | * | ||
| 1087 | * Prepare a blank set of credentials for modification. This must allocate all | ||
| 1088 | * the memory the LSM module might require such that cred_transfer() can | ||
| 1089 | * complete without error. | ||
| 1090 | */ | ||
| 1091 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 1092 | { | ||
| 1093 | cred->security = NULL; | ||
| 1094 | return 0; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | |||
| 1098 | /** | ||
| 1083 | * smack_cred_free - "free" task-level security credentials | 1099 | * smack_cred_free - "free" task-level security credentials |
| 1084 | * @cred: the credentials in question | 1100 | * @cred: the credentials in question |
| 1085 | * | 1101 | * |
| @@ -1117,6 +1133,18 @@ static void smack_cred_commit(struct cred *new, const struct cred *old) | |||
| 1117 | } | 1133 | } |
| 1118 | 1134 | ||
| 1119 | /** | 1135 | /** |
| 1136 | * smack_cred_transfer - Transfer the old credentials to the new credentials | ||
| 1137 | * @new: the new credentials | ||
| 1138 | * @old: the original credentials | ||
| 1139 | * | ||
| 1140 | * Fill in a set of blank credentials from another set of credentials. | ||
| 1141 | */ | ||
| 1142 | static void smack_cred_transfer(struct cred *new, const struct cred *old) | ||
| 1143 | { | ||
| 1144 | new->security = old->security; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /** | ||
| 1120 | * smack_kernel_act_as - Set the subjective context in a set of credentials | 1148 | * smack_kernel_act_as - Set the subjective context in a set of credentials |
| 1121 | * @new: points to the set of credentials to be modified. | 1149 | * @new: points to the set of credentials to be modified. |
| 1122 | * @secid: specifies the security ID to be set | 1150 | * @secid: specifies the security ID to be set |
| @@ -3073,9 +3101,11 @@ struct security_operations smack_ops = { | |||
| 3073 | .file_send_sigiotask = smack_file_send_sigiotask, | 3101 | .file_send_sigiotask = smack_file_send_sigiotask, |
| 3074 | .file_receive = smack_file_receive, | 3102 | .file_receive = smack_file_receive, |
| 3075 | 3103 | ||
| 3104 | .cred_alloc_blank = smack_cred_alloc_blank, | ||
| 3076 | .cred_free = smack_cred_free, | 3105 | .cred_free = smack_cred_free, |
| 3077 | .cred_prepare = smack_cred_prepare, | 3106 | .cred_prepare = smack_cred_prepare, |
| 3078 | .cred_commit = smack_cred_commit, | 3107 | .cred_commit = smack_cred_commit, |
| 3108 | .cred_transfer = smack_cred_transfer, | ||
| 3079 | .kernel_act_as = smack_kernel_act_as, | 3109 | .kernel_act_as = smack_kernel_act_as, |
| 3080 | .kernel_create_files_as = smack_kernel_create_files_as, | 3110 | .kernel_create_files_as = smack_kernel_create_files_as, |
| 3081 | .task_setpgid = smack_task_setpgid, | 3111 | .task_setpgid = smack_task_setpgid, |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 35a13e7915e4..9548a0984cc4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
| @@ -14,6 +14,12 @@ | |||
| 14 | #include "tomoyo.h" | 14 | #include "tomoyo.h" |
| 15 | #include "realpath.h" | 15 | #include "realpath.h" |
| 16 | 16 | ||
| 17 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | ||
| 18 | { | ||
| 19 | new->security = NULL; | ||
| 20 | return 0; | ||
| 21 | } | ||
| 22 | |||
| 17 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 23 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
| 18 | gfp_t gfp) | 24 | gfp_t gfp) |
| 19 | { | 25 | { |
| @@ -25,6 +31,15 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | |||
| 25 | return 0; | 31 | return 0; |
| 26 | } | 32 | } |
| 27 | 33 | ||
| 34 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | ||
| 35 | { | ||
| 36 | /* | ||
| 37 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | ||
| 38 | * we don't need to duplicate. | ||
| 39 | */ | ||
| 40 | new->security = old->security; | ||
| 41 | } | ||
| 42 | |||
| 28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
| 29 | { | 44 | { |
| 30 | int rc; | 45 | int rc; |
| @@ -262,7 +277,9 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
| 262 | */ | 277 | */ |
| 263 | static struct security_operations tomoyo_security_ops = { | 278 | static struct security_operations tomoyo_security_ops = { |
| 264 | .name = "tomoyo", | 279 | .name = "tomoyo", |
| 280 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | ||
| 265 | .cred_prepare = tomoyo_cred_prepare, | 281 | .cred_prepare = tomoyo_cred_prepare, |
| 282 | .cred_transfer = tomoyo_cred_transfer, | ||
| 266 | .bprm_set_creds = tomoyo_bprm_set_creds, | 283 | .bprm_set_creds = tomoyo_bprm_set_creds, |
| 267 | .bprm_check_security = tomoyo_bprm_check_security, | 284 | .bprm_check_security = tomoyo_bprm_check_security, |
| 268 | #ifdef CONFIG_SYSCTL | 285 | #ifdef CONFIG_SYSCTL |
