Commit 68463510 authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Thomas Gleixner

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: default avatarDmitry Safonov <dsafonov@virtuozzo.com>
Reviewed-by: default avatarAndy 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.comSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent cc87324b
...@@ -378,7 +378,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, ...@@ -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_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
} put_user_catch(err); } 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, err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]); regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
......
...@@ -19,6 +19,12 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, ...@@ -19,6 +19,12 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
# define ia32_setup_rt_frame __setup_rt_frame # define ia32_setup_rt_frame __setup_rt_frame
#endif #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, extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
struct task_struct *tsk); struct task_struct *tsk);
extern void convert_to_fxsr(struct task_struct *tsk, extern void convert_to_fxsr(struct task_struct *tsk,
......
...@@ -23,6 +23,10 @@ typedef struct { ...@@ -23,6 +23,10 @@ typedef struct {
unsigned long sig[_NSIG_WORDS]; unsigned long sig[_NSIG_WORDS];
} sigset_t; } sigset_t;
/* non-uapi in-kernel SA_FLAGS for those indicates ABI for a signal frame */
#define SA_IA32_ABI 0x02000000u
#define SA_X32_ABI 0x01000000u
#ifndef CONFIG_COMPAT #ifndef CONFIG_COMPAT
typedef sigset_t compat_sigset_t; typedef sigset_t compat_sigset_t;
#endif #endif
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <asm/syscalls.h> #include <asm/syscalls.h>
#include <asm/sigframe.h> #include <asm/sigframe.h>
#include <asm/signal.h>
#define COPY(x) do { \ #define COPY(x) do { \
get_user_ex(regs->x, &sc->x); \ get_user_ex(regs->x, &sc->x); \
...@@ -547,7 +548,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig, ...@@ -547,7 +548,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
return -EFAULT; return -EFAULT;
if (ksig->ka.sa.sa_flags & SA_SIGINFO) { 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; return -EFAULT;
} }
...@@ -660,20 +661,21 @@ asmlinkage long sys_rt_sigreturn(void) ...@@ -660,20 +661,21 @@ asmlinkage long sys_rt_sigreturn(void)
return 0; return 0;
} }
static inline int is_ia32_compat_frame(void) static inline int is_ia32_compat_frame(struct ksignal *ksig)
{ {
return IS_ENABLED(CONFIG_IA32_EMULATION) && return IS_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 IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(); return IS_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 IS_ENABLED(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32); return IS_ENABLED(CONFIG_X86_X32_ABI) &&
ksig->ka.sa.sa_flags & SA_X32_ABI;
} }
static int static int
...@@ -684,12 +686,12 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) ...@@ -684,12 +686,12 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
compat_sigset_t *cset = (compat_sigset_t *) set; compat_sigset_t *cset = (compat_sigset_t *) set;
/* Set up the stack frame */ /* Set up the stack frame */
if (is_ia32_frame()) { if (is_ia32_frame(ksig)) {
if (ksig->ka.sa.sa_flags & SA_SIGINFO) if (ksig->ka.sa.sa_flags & SA_SIGINFO)
return ia32_setup_rt_frame(usig, ksig, cset, regs); return ia32_setup_rt_frame(usig, ksig, cset, regs);
else else
return ia32_setup_frame(usig, ksig, cset, regs); 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); return x32_setup_rt_frame(ksig, cset, regs);
} else { } else {
return __setup_rt_frame(ksig->sig, ksig, set, regs); return __setup_rt_frame(ksig->sig, ksig, set, regs);
......
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/ptrace.h>
/* /*
* The compat_siginfo_t structure and handing code is very easy * The compat_siginfo_t structure and handing code is very easy
...@@ -92,10 +93,31 @@ static inline void signal_compat_build_tests(void) ...@@ -92,10 +93,31 @@ static inline void signal_compat_build_tests(void)
/* any new si_fields should be added here */ /* any new si_fields should be added here */
} }
int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
{
/* Don't leak in-kernel non-uapi flags to user-space */
if (oact)
oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
if (!act)
return;
/* Don't let flags to be set from userspace */
act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
if (user_64bit_mode(current_pt_regs()))
return;
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; int err = 0;
bool ia32 = test_thread_flag(TIF_IA32);
signal_compat_build_tests(); signal_compat_build_tests();
...@@ -146,7 +168,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -146,7 +168,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
put_user_ex(from->si_arch, &to->si_arch); put_user_ex(from->si_arch, &to->si_arch);
break; break;
case __SI_CHLD >> 16: case __SI_CHLD >> 16:
if (ia32) { if (!x32_ABI) {
put_user_ex(from->si_utime, &to->si_utime); put_user_ex(from->si_utime, &to->si_utime);
put_user_ex(from->si_stime, &to->si_stime); put_user_ex(from->si_stime, &to->si_stime);
} else { } else {
...@@ -180,6 +202,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -180,6 +202,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
return err; 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 copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{ {
int err = 0; int err = 0;
......
...@@ -3044,6 +3044,11 @@ void kernel_sigaction(int sig, __sighandler_t action) ...@@ -3044,6 +3044,11 @@ void kernel_sigaction(int sig, __sighandler_t action)
} }
EXPORT_SYMBOL(kernel_sigaction); EXPORT_SYMBOL(kernel_sigaction);
void __weak sigaction_compat_abi(struct k_sigaction *act,
struct k_sigaction *oact)
{
}
int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
{ {
struct task_struct *p = current, *t; struct task_struct *p = current, *t;
...@@ -3059,6 +3064,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) ...@@ -3059,6 +3064,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
if (oact) if (oact)
*oact = *k; *oact = *k;
sigaction_compat_abi(act, oact);
if (act) { if (act) {
sigdelsetmask(&act->sa.sa_mask, sigdelsetmask(&act->sa.sa_mask,
sigmask(SIGKILL) | sigmask(SIGSTOP)); sigmask(SIGKILL) | sigmask(SIGSTOP));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment