aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Safonov <dsafonov@virtuozzo.com>2016-09-05 09:33:08 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-09-14 15:28:11 -0400
commit6846351052e685c2d1428e80ead2d7ca3d7ed913 (patch)
tree5bc4ba09c325f2cd672e793f3c23f69b206bea19
parentcc87324b3dbb9bdf6916c7f479230db24c4aa309 (diff)
x86/signal: Add SA_{X32,IA32}_ABI sa_flags
Introduce new flags that defines which ABI to use on creating sigframe. Those flags kernel will set according to sigaction syscall ABI, which set handler for the signal being delivered. So that will drop the dependency on TIF_IA32/TIF_X32 flags on signal deliver. Those flags will be used only under CONFIG_COMPAT. Similar way ARM uses sa_flags to differ in which mode deliver signal for 26-bit applications (look at SA_THIRYTWO). Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com> Reviewed-by: Andy Lutomirski <luto@kernel.org> Cc: 0x7f454c46@gmail.com Cc: oleg@redhat.com Cc: linux-mm@kvack.org Cc: gorcunov@openvz.org Cc: xemul@virtuozzo.com Link: http://lkml.kernel.org/r/20160905133308.28234-7-dsafonov@virtuozzo.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/ia32/ia32_signal.c2
-rw-r--r--arch/x86/include/asm/fpu/signal.h6
-rw-r--r--arch/x86/include/asm/signal.h4
-rw-r--r--arch/x86/kernel/signal.c20
-rw-r--r--arch/x86/kernel/signal_compat.c34
-rw-r--r--kernel/signal.c7
6 files changed, 60 insertions, 13 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 2f29f4e407c3..cb13c0564ea7 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -378,7 +378,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
378 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); 378 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
379 } put_user_catch(err); 379 } put_user_catch(err);
380 380
381 err |= copy_siginfo_to_user32(&frame->info, &ksig->info); 381 err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false);
382 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, 382 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
383 regs, set->sig[0]); 383 regs, set->sig[0]);
384 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 384 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
index 0e970d00dfcd..20a1fbf7fe4e 100644
--- a/arch/x86/include/asm/fpu/signal.h
+++ b/arch/x86/include/asm/fpu/signal.h
@@ -19,6 +19,12 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
19# define ia32_setup_rt_frame __setup_rt_frame 19# define ia32_setup_rt_frame __setup_rt_frame
20#endif 20#endif
21 21
22#ifdef CONFIG_COMPAT
23int __copy_siginfo_to_user32(compat_siginfo_t __user *to,
24 const siginfo_t *from, bool x32_ABI);
25#endif
26
27
22extern void convert_from_fxsr(struct user_i387_ia32_struct *env, 28extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
23 struct task_struct *tsk); 29 struct task_struct *tsk);
24extern void convert_to_fxsr(struct task_struct *tsk, 30extern void convert_to_fxsr(struct task_struct *tsk,
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index dd1e7d6387ab..8af22be0fe61 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -23,6 +23,10 @@ typedef struct {
23 unsigned long sig[_NSIG_WORDS]; 23 unsigned long sig[_NSIG_WORDS];
24} sigset_t; 24} sigset_t;
25 25
26/* non-uapi in-kernel SA_FLAGS for those indicates ABI for a signal frame */
27#define SA_IA32_ABI 0x02000000u
28#define SA_X32_ABI 0x01000000u
29
26#ifndef CONFIG_COMPAT 30#ifndef CONFIG_COMPAT
27typedef sigset_t compat_sigset_t; 31typedef sigset_t compat_sigset_t;
28#endif 32#endif
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 04cb3212db2d..b1a5d252d482 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -42,6 +42,7 @@
42#include <asm/syscalls.h> 42#include <asm/syscalls.h>
43 43
44#include <asm/sigframe.h> 44#include <asm/sigframe.h>
45#include <asm/signal.h>
45 46
46#define COPY(x) do { \ 47#define COPY(x) do { \
47 get_user_ex(regs->x, &sc->x); \ 48 get_user_ex(regs->x, &sc->x); \
@@ -547,7 +548,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
547 return -EFAULT; 548 return -EFAULT;
548 549
549 if (ksig->ka.sa.sa_flags & SA_SIGINFO) { 550 if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
550 if (copy_siginfo_to_user32(&frame->info, &ksig->info)) 551 if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
551 return -EFAULT; 552 return -EFAULT;
552 } 553 }
553 554
@@ -660,20 +661,21 @@ badframe:
660 return 0; 661 return 0;
661} 662}
662 663
663static inline int is_ia32_compat_frame(void) 664static inline int is_ia32_compat_frame(struct ksignal *ksig)
664{ 665{
665 return IS_ENABLED(CONFIG_IA32_EMULATION) && 666 return IS_ENABLED(CONFIG_IA32_EMULATION) &&
666 test_thread_flag(TIF_IA32); 667 ksig->ka.sa.sa_flags & SA_IA32_ABI;
667} 668}
668 669
669static inline int is_ia32_frame(void) 670static inline int is_ia32_frame(struct ksignal *ksig)
670{ 671{
671 return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(); 672 return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig);
672} 673}
673 674
674static inline int is_x32_frame(void) 675static inline int is_x32_frame(struct ksignal *ksig)
675{ 676{
676 return IS_ENABLED(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32); 677 return IS_ENABLED(CONFIG_X86_X32_ABI) &&
678 ksig->ka.sa.sa_flags & SA_X32_ABI;
677} 679}
678 680
679static int 681static int
@@ -684,12 +686,12 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
684 compat_sigset_t *cset = (compat_sigset_t *) set; 686 compat_sigset_t *cset = (compat_sigset_t *) set;
685 687
686 /* Set up the stack frame */ 688 /* Set up the stack frame */
687 if (is_ia32_frame()) { 689 if (is_ia32_frame(ksig)) {
688 if (ksig->ka.sa.sa_flags & SA_SIGINFO) 690 if (ksig->ka.sa.sa_flags & SA_SIGINFO)
689 return ia32_setup_rt_frame(usig, ksig, cset, regs); 691 return ia32_setup_rt_frame(usig, ksig, cset, regs);
690 else 692 else
691 return ia32_setup_frame(usig, ksig, cset, regs); 693 return ia32_setup_frame(usig, ksig, cset, regs);
692 } else if (is_x32_frame()) { 694 } else if (is_x32_frame(ksig)) {
693 return x32_setup_rt_frame(ksig, cset, regs); 695 return x32_setup_rt_frame(ksig, cset, regs);
694 } else { 696 } else {
695 return __setup_rt_frame(ksig->sig, ksig, set, regs); 697 return __setup_rt_frame(ksig->sig, ksig, set, regs);
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index b44564bf86a8..40df33753bae 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -1,5 +1,6 @@
1#include <linux/compat.h> 1#include <linux/compat.h>
2#include <linux/uaccess.h> 2#include <linux/uaccess.h>
3#include <linux/ptrace.h>
3 4
4/* 5/*
5 * The compat_siginfo_t structure and handing code is very easy 6 * The compat_siginfo_t structure and handing code is very easy
@@ -92,10 +93,31 @@ static inline void signal_compat_build_tests(void)
92 /* any new si_fields should be added here */ 93 /* any new si_fields should be added here */
93} 94}
94 95
95int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) 96void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
97{
98 /* Don't leak in-kernel non-uapi flags to user-space */
99 if (oact)
100 oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
101
102 if (!act)
103 return;
104
105 /* Don't let flags to be set from userspace */
106 act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
107
108 if (user_64bit_mode(current_pt_regs()))
109 return;
110
111 if (in_ia32_syscall())
112 act->sa.sa_flags |= SA_IA32_ABI;
113 if (in_x32_syscall())
114 act->sa.sa_flags |= SA_X32_ABI;
115}
116
117int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
118 bool x32_ABI)
96{ 119{
97 int err = 0; 120 int err = 0;
98 bool ia32 = test_thread_flag(TIF_IA32);
99 121
100 signal_compat_build_tests(); 122 signal_compat_build_tests();
101 123
@@ -146,7 +168,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
146 put_user_ex(from->si_arch, &to->si_arch); 168 put_user_ex(from->si_arch, &to->si_arch);
147 break; 169 break;
148 case __SI_CHLD >> 16: 170 case __SI_CHLD >> 16:
149 if (ia32) { 171 if (!x32_ABI) {
150 put_user_ex(from->si_utime, &to->si_utime); 172 put_user_ex(from->si_utime, &to->si_utime);
151 put_user_ex(from->si_stime, &to->si_stime); 173 put_user_ex(from->si_stime, &to->si_stime);
152 } else { 174 } else {
@@ -180,6 +202,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
180 return err; 202 return err;
181} 203}
182 204
205/* from syscall's path, where we know the ABI */
206int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
207{
208 return __copy_siginfo_to_user32(to, from, in_x32_syscall());
209}
210
183int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) 211int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
184{ 212{
185 int err = 0; 213 int err = 0;
diff --git a/kernel/signal.c b/kernel/signal.c
index af21afc00d08..75761acc77cf 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3044,6 +3044,11 @@ void kernel_sigaction(int sig, __sighandler_t action)
3044} 3044}
3045EXPORT_SYMBOL(kernel_sigaction); 3045EXPORT_SYMBOL(kernel_sigaction);
3046 3046
3047void __weak sigaction_compat_abi(struct k_sigaction *act,
3048 struct k_sigaction *oact)
3049{
3050}
3051
3047int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) 3052int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
3048{ 3053{
3049 struct task_struct *p = current, *t; 3054 struct task_struct *p = current, *t;
@@ -3059,6 +3064,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
3059 if (oact) 3064 if (oact)
3060 *oact = *k; 3065 *oact = *k;
3061 3066
3067 sigaction_compat_abi(act, oact);
3068
3062 if (act) { 3069 if (act) {
3063 sigdelsetmask(&act->sa.sa_mask, 3070 sigdelsetmask(&act->sa.sa_mask,
3064 sigmask(SIGKILL) | sigmask(SIGSTOP)); 3071 sigmask(SIGKILL) | sigmask(SIGSTOP));