Skip to content

Commit 6846351

Browse files
0x7f454c46KAGA-KOKO
authored andcommitted
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 <[email protected]> Reviewed-by: Andy Lutomirski <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent cc87324 commit 6846351

File tree

6 files changed

+60
-13
lines changed

6 files changed

+60
-13
lines changed

arch/x86/ia32/ia32_signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
378378
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
379379
} put_user_catch(err);
380380

381-
err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
381+
err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false);
382382
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
383383
regs, set->sig[0]);
384384
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

arch/x86/include/asm/fpu/signal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
1919
# define ia32_setup_rt_frame __setup_rt_frame
2020
#endif
2121

22+
#ifdef CONFIG_COMPAT
23+
int __copy_siginfo_to_user32(compat_siginfo_t __user *to,
24+
const siginfo_t *from, bool x32_ABI);
25+
#endif
26+
27+
2228
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
2329
struct task_struct *tsk);
2430
extern void convert_to_fxsr(struct task_struct *tsk,

arch/x86/include/asm/signal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ typedef struct {
2323
unsigned long sig[_NSIG_WORDS];
2424
} sigset_t;
2525

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+
2630
#ifndef CONFIG_COMPAT
2731
typedef sigset_t compat_sigset_t;
2832
#endif

arch/x86/kernel/signal.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <asm/syscalls.h>
4343

4444
#include <asm/sigframe.h>
45+
#include <asm/signal.h>
4546

4647
#define COPY(x) do { \
4748
get_user_ex(regs->x, &sc->x); \
@@ -547,7 +548,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
547548
return -EFAULT;
548549

549550
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))
551552
return -EFAULT;
552553
}
553554

@@ -660,20 +661,21 @@ asmlinkage long sys_rt_sigreturn(void)
660661
return 0;
661662
}
662663

663-
static inline int is_ia32_compat_frame(void)
664+
static inline int is_ia32_compat_frame(struct ksignal *ksig)
664665
{
665666
return IS_ENABLED(CONFIG_IA32_EMULATION) &&
666-
test_thread_flag(TIF_IA32);
667+
ksig->ka.sa.sa_flags & SA_IA32_ABI;
667668
}
668669

669-
static inline int is_ia32_frame(void)
670+
static inline int is_ia32_frame(struct ksignal *ksig)
670671
{
671-
return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame();
672+
return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig);
672673
}
673674

674-
static inline int is_x32_frame(void)
675+
static inline int is_x32_frame(struct ksignal *ksig)
675676
{
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;
677679
}
678680

679681
static int
@@ -684,12 +686,12 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
684686
compat_sigset_t *cset = (compat_sigset_t *) set;
685687

686688
/* Set up the stack frame */
687-
if (is_ia32_frame()) {
689+
if (is_ia32_frame(ksig)) {
688690
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
689691
return ia32_setup_rt_frame(usig, ksig, cset, regs);
690692
else
691693
return ia32_setup_frame(usig, ksig, cset, regs);
692-
} else if (is_x32_frame()) {
694+
} else if (is_x32_frame(ksig)) {
693695
return x32_setup_rt_frame(ksig, cset, regs);
694696
} else {
695697
return __setup_rt_frame(ksig->sig, ksig, set, regs);

arch/x86/kernel/signal_compat.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <linux/compat.h>
22
#include <linux/uaccess.h>
3+
#include <linux/ptrace.h>
34

45
/*
56
* The compat_siginfo_t structure and handing code is very easy
@@ -92,10 +93,31 @@ static inline void signal_compat_build_tests(void)
9293
/* any new si_fields should be added here */
9394
}
9495

95-
int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
96+
void 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+
117+
int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
118+
bool x32_ABI)
96119
{
97120
int err = 0;
98-
bool ia32 = test_thread_flag(TIF_IA32);
99121

100122
signal_compat_build_tests();
101123

@@ -146,7 +168,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
146168
put_user_ex(from->si_arch, &to->si_arch);
147169
break;
148170
case __SI_CHLD >> 16:
149-
if (ia32) {
171+
if (!x32_ABI) {
150172
put_user_ex(from->si_utime, &to->si_utime);
151173
put_user_ex(from->si_stime, &to->si_stime);
152174
} else {
@@ -180,6 +202,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
180202
return err;
181203
}
182204

205+
/* from syscall's path, where we know the ABI */
206+
int 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+
183211
int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
184212
{
185213
int err = 0;

kernel/signal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,6 +3044,11 @@ void kernel_sigaction(int sig, __sighandler_t action)
30443044
}
30453045
EXPORT_SYMBOL(kernel_sigaction);
30463046

3047+
void __weak sigaction_compat_abi(struct k_sigaction *act,
3048+
struct k_sigaction *oact)
3049+
{
3050+
}
3051+
30473052
int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
30483053
{
30493054
struct task_struct *p = current, *t;
@@ -3059,6 +3064,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
30593064
if (oact)
30603065
*oact = *k;
30613066

3067+
sigaction_compat_abi(act, oact);
3068+
30623069
if (act) {
30633070
sigdelsetmask(&act->sa.sa_mask,
30643071
sigmask(SIGKILL) | sigmask(SIGSTOP));

0 commit comments

Comments
 (0)