Skip to content

Commit c6f2062

Browse files
amlutoIngo Molnar
authored andcommitted
x86/signal/64: Fix SS handling for signals delivered to 64-bit programs
The comment in the signal code says that apps can save/restore other segments on their own. It's true that apps can *save* SS on their own, but there's no way for apps to restore it: SYSCALL effectively resets SS to __USER_DS, so any value that user code tries to load into SS gets lost on entry to sigreturn. This recycles two padding bytes in the segment selector area for SS. While we're at it, we need a second change to make this useful. If the signal we're delivering is caused by a bad SS value, saving that value isn't enough. We need to remove that bad value from the regs before we try to deliver the signal. Oddly, the i386 code already got this right. I suspect that 64-bit programs that try to run 16-bit code and use signals will have a lot of trouble without this. Signed-off-by: Andy Lutomirski <[email protected]> Reviewed-by: Oleg Nesterov <[email protected]> Acked-by: Borislav Petkov <[email protected]> Cc: Al Viro <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lkml.kernel.org/r/405594361340a2ec32f8e2b115c142df0e180d8e.1426193719.git.luto@kernel.org Signed-off-by: Ingo Molnar <[email protected]>
1 parent 263042e commit c6f2062

File tree

3 files changed

+15
-11
lines changed

3 files changed

+15
-11
lines changed

arch/x86/include/asm/sigcontext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct sigcontext {
5959
unsigned short cs;
6060
unsigned short gs;
6161
unsigned short fs;
62-
unsigned short __pad0;
62+
unsigned short ss;
6363
unsigned long err;
6464
unsigned long trapno;
6565
unsigned long oldmask;

arch/x86/include/uapi/asm/sigcontext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ struct sigcontext {
179179
__u16 cs;
180180
__u16 gs;
181181
__u16 fs;
182-
__u16 __pad0;
182+
__u16 ss;
183183
__u64 err;
184184
__u64 trapno;
185185
__u64 oldmask;

arch/x86/kernel/signal.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
9494
COPY(r15);
9595
#endif /* CONFIG_X86_64 */
9696

97-
#ifdef CONFIG_X86_32
9897
COPY_SEG_CPL3(cs);
9998
COPY_SEG_CPL3(ss);
100-
#else /* !CONFIG_X86_32 */
101-
/* Kernel saves and restores only the CS segment register on signals,
102-
* which is the bare minimum needed to allow mixed 32/64-bit code.
103-
* App's signal handler can save/restore other segments if needed. */
104-
COPY_SEG_CPL3(cs);
105-
#endif /* CONFIG_X86_32 */
10699

107100
get_user_ex(tmpflags, &sc->flags);
108101
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
@@ -164,6 +157,7 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
164157
put_user_ex(regs->cs, &sc->cs);
165158
put_user_ex(0, &sc->gs);
166159
put_user_ex(0, &sc->fs);
160+
put_user_ex(regs->ss, &sc->ss);
167161
#endif /* CONFIG_X86_32 */
168162

169163
put_user_ex(fpstate, &sc->fpstate);
@@ -457,9 +451,19 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
457451

458452
regs->sp = (unsigned long)frame;
459453

460-
/* Set up the CS register to run signal handlers in 64-bit mode,
461-
even if the handler happens to be interrupting 32-bit code. */
454+
/*
455+
* Set up the CS and SS registers to run signal handlers in
456+
* 64-bit mode, even if the handler happens to be interrupting
457+
* 32-bit or 16-bit code.
458+
*
459+
* SS is subtle. In 64-bit mode, we don't need any particular
460+
* SS descriptor, but we do need SS to be valid. It's possible
461+
* that the old SS is entirely bogus -- this can happen if the
462+
* signal we're trying to deliver is #GP or #SS caused by a bad
463+
* SS value.
464+
*/
462465
regs->cs = __USER_CS;
466+
regs->ss = __USER_DS;
463467

464468
return 0;
465469
}

0 commit comments

Comments
 (0)