On Mon, Apr 25, 2016 at 9:12 AM, Dmitry Safonov <dsafo...@virtuozzo.com> wrote: > Introduce new flags that defines which ABI to use on creating sigframe. > Those flags one may set from the userspace, or kernel will set them > according to syscall, which sets handler for a signal. > So that will drop the dependency on TIF_IA32/TIF_X32 flags on syscall deliver. > Those flags will be used only under CONFIG_COMPAT. > > The same way ARM uses sa_flags to differ in which mode deliver signal > for 26-bit applications (look at SA_THIRYTWO).
Hmm. Do we want to make these user-visible at all, or should it be purely an in-kernel thing? --Andy > > Cc: Andy Lutomirski <l...@kernel.org> > Cc: Ingo Molnar <mi...@redhat.com> > Cc: Thomas Gleixner <t...@linutronix.de> > Cc: "H. Peter Anvin" <h...@zytor.com> > Cc: x...@kernel.org > Signed-off-by: Dmitry Safonov <dsafo...@virtuozzo.com> > --- > arch/x86/ia32/ia32_signal.c | 2 +- > arch/x86/include/asm/fpu/signal.h | 6 ++++++ > arch/x86/include/uapi/asm/signal.h | 6 +++++- > arch/x86/kernel/signal.c | 19 ++++++++++--------- > arch/x86/kernel/signal_compat.c | 33 ++++++++++++++++++++++++++++++--- > kernel/signal.c | 5 +++++ > 6 files changed, 57 insertions(+), 14 deletions(-) > > diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c > index 0552884da18d..faf1871300cb 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, > put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); > } put_user_catch(err); > > - err |= copy_siginfo_to_user32(&frame->info, &ksig->info); > + err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false); > err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, > regs, set->sig[0]); > 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, > # define ia32_setup_rt_frame __setup_rt_frame > #endif > > +#ifdef CONFIG_COMPAT > +int __copy_siginfo_to_user32(compat_siginfo_t __user *to, > + const siginfo_t *from, bool x32_ABI); > +#endif > + > + > extern void convert_from_fxsr(struct user_i387_ia32_struct *env, > struct task_struct *tsk); > extern void convert_to_fxsr(struct task_struct *tsk, > diff --git a/arch/x86/include/uapi/asm/signal.h > b/arch/x86/include/uapi/asm/signal.h > index 8264f47cf53e..9c663b6fc023 100644 > --- a/arch/x86/include/uapi/asm/signal.h > +++ b/arch/x86/include/uapi/asm/signal.h > @@ -70,6 +70,8 @@ typedef unsigned long sigset_t; > * SA_RESETHAND clears the handler when the signal is delivered. > * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. > * SA_NODEFER prevents the current signal from being masked in the handler. > + * SA_IA32_ABI/SA_X32_ABI indicates ABI for a signal frame, > + * if neither is set, the kernel will set them according to a syscall ABI > * > * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single > * Unix names RESETHAND and NODEFER respectively. > @@ -85,7 +87,9 @@ typedef unsigned long sigset_t; > #define SA_NOMASK SA_NODEFER > #define SA_ONESHOT SA_RESETHAND > > -#define SA_RESTORER 0x04000000 > +#define SA_RESTORER 0x04000000u > +#define SA_IA32_ABI 0x02000000u > +#define SA_X32_ABI 0x01000000u > > #define MINSIGSTKSZ 2048 > #define SIGSTKSZ 8192 > diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c > index aa31265aa61d..8d13556f7df2 100644 > --- a/arch/x86/kernel/signal.c > +++ b/arch/x86/kernel/signal.c > @@ -548,7 +548,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig, > return -EFAULT; > > if (ksig->ka.sa.sa_flags & SA_SIGINFO) { > - if (copy_siginfo_to_user32(&frame->info, &ksig->info)) > + if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true)) > return -EFAULT; > } > > @@ -661,20 +661,21 @@ badframe: > return 0; > } > > -static inline int is_ia32_compat_frame(void) > +static inline int is_ia32_compat_frame(struct ksignal *ksig) > { > return config_enabled(CONFIG_IA32_EMULATION) && > - test_thread_flag(TIF_IA32); > + ksig->ka.sa.sa_flags & SA_IA32_ABI; > } > > -static inline int is_ia32_frame(void) > +static inline int is_ia32_frame(struct ksignal *ksig) > { > - return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame(); > + return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame(ksig); > } > > -static inline int is_x32_frame(void) > +static inline int is_x32_frame(struct ksignal *ksig) > { > - return config_enabled(CONFIG_X86_X32_ABI) && > test_thread_flag(TIF_X32); > + return config_enabled(CONFIG_X86_X32_ABI) && > + ksig->ka.sa.sa_flags & SA_X32_ABI; > } > > static int > @@ -685,12 +686,12 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs > *regs) > compat_sigset_t *cset = (compat_sigset_t *) set; > > /* Set up the stack frame */ > - if (is_ia32_frame()) { > + if (is_ia32_frame(ksig)) { > if (ksig->ka.sa.sa_flags & SA_SIGINFO) > return ia32_setup_rt_frame(usig, ksig, cset, regs); > else > return ia32_setup_frame(usig, ksig, cset, regs); > - } else if (is_x32_frame()) { > + } else if (is_x32_frame(ksig)) { > return x32_setup_rt_frame(ksig, cset, regs); > } else { > 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 dc3c0b1c816f..7f2d7c784a47 100644 > --- a/arch/x86/kernel/signal_compat.c > +++ b/arch/x86/kernel/signal_compat.c > @@ -1,10 +1,31 @@ > #include <linux/compat.h> > #include <linux/uaccess.h> > +#include <linux/ptrace.h> > > -int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t > *from) > +void sigaction_compat_abi(struct k_sigaction *act) > +{ > + if (!act) > + return; > + > + /* don't let to set both ABI flags */ > + if (act->sa.sa_flags & SA_IA32_ABI && act->sa.sa_flags & SA_X32_ABI) > + act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI); > + > + if (user_64bit_mode(current_pt_regs())) > + return; > + > + if (!(act->sa.sa_flags & (SA_IA32_ABI | SA_X32_ABI))) { > + if (in_ia32_syscall()) > + act->sa.sa_flags |= SA_IA32_ABI; > + if (in_x32_syscall()) > + act->sa.sa_flags |= SA_X32_ABI; > + } > +} > + > +int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t > *from, > + bool x32_ABI) > { > int err = 0; > - bool ia32 = test_thread_flag(TIF_IA32); > > if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) > return -EFAULT; > @@ -38,7 +59,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, > const siginfo_t *from) > put_user_ex(from->si_arch, &to->si_arch); > break; > case __SI_CHLD >> 16: > - if (ia32) { > + if (!x32_ABI) { > put_user_ex(from->si_utime, > &to->si_utime); > put_user_ex(from->si_stime, > &to->si_stime); > } else { > @@ -72,6 +93,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, > const siginfo_t *from) > return err; > } > > +/* from syscall's path, where we know the ABI */ > +int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t > *from) > +{ > + return __copy_siginfo_to_user32(to, from, in_x32_syscall()); > +} > + > int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) > { > int err = 0; > diff --git a/kernel/signal.c b/kernel/signal.c > index aa9bf00749c1..d0309f2a36f0 100644 > --- a/kernel/signal.c > +++ b/kernel/signal.c > @@ -3048,6 +3048,10 @@ void kernel_sigaction(int sig, __sighandler_t action) > } > EXPORT_SYMBOL(kernel_sigaction); > > +void __weak sigaction_compat_abi(struct k_sigaction *act) > +{ > +} > + > int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) > { > struct task_struct *p = current, *t; > @@ -3058,6 +3062,7 @@ int do_sigaction(int sig, struct k_sigaction *act, > struct k_sigaction *oact) > return -EINVAL; > > k = &p->sighand->action[sig-1]; > + sigaction_compat_abi(act); > > spin_lock_irq(&p->sighand->siglock); > if (oact) > -- > 2.8.0 > -- Andy Lutomirski AMA Capital Management, LLC