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 |