diff options
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 26 |
1 files changed, 11 insertions, 15 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 206996c1669d..71820c42b6ce 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -93,8 +93,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
93 | COPY(r15); | 93 | COPY(r15); |
94 | #endif /* CONFIG_X86_64 */ | 94 | #endif /* CONFIG_X86_64 */ |
95 | 95 | ||
96 | #ifdef CONFIG_X86_32 | ||
96 | COPY_SEG_CPL3(cs); | 97 | COPY_SEG_CPL3(cs); |
97 | COPY_SEG_CPL3(ss); | 98 | COPY_SEG_CPL3(ss); |
99 | #else /* !CONFIG_X86_32 */ | ||
100 | /* Kernel saves and restores only the CS segment register on signals, | ||
101 | * which is the bare minimum needed to allow mixed 32/64-bit code. | ||
102 | * App's signal handler can save/restore other segments if needed. */ | ||
103 | COPY_SEG_CPL3(cs); | ||
104 | #endif /* CONFIG_X86_32 */ | ||
98 | 105 | ||
99 | get_user_ex(tmpflags, &sc->flags); | 106 | get_user_ex(tmpflags, &sc->flags); |
100 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 107 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
@@ -154,9 +161,8 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
154 | #else /* !CONFIG_X86_32 */ | 161 | #else /* !CONFIG_X86_32 */ |
155 | put_user_ex(regs->flags, &sc->flags); | 162 | put_user_ex(regs->flags, &sc->flags); |
156 | put_user_ex(regs->cs, &sc->cs); | 163 | put_user_ex(regs->cs, &sc->cs); |
157 | put_user_ex(0, &sc->__pad2); | 164 | put_user_ex(0, &sc->gs); |
158 | put_user_ex(0, &sc->__pad1); | 165 | put_user_ex(0, &sc->fs); |
159 | put_user_ex(regs->ss, &sc->ss); | ||
160 | #endif /* CONFIG_X86_32 */ | 166 | #endif /* CONFIG_X86_32 */ |
161 | 167 | ||
162 | put_user_ex(fpstate, &sc->fpstate); | 168 | put_user_ex(fpstate, &sc->fpstate); |
@@ -451,19 +457,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, | |||
451 | 457 | ||
452 | regs->sp = (unsigned long)frame; | 458 | regs->sp = (unsigned long)frame; |
453 | 459 | ||
454 | /* | 460 | /* Set up the CS register to run signal handlers in 64-bit mode, |
455 | * Set up the CS and SS registers to run signal handlers in | 461 | even if the handler happens to be interrupting 32-bit code. */ |
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 | */ | ||
465 | regs->cs = __USER_CS; | 462 | regs->cs = __USER_CS; |
466 | regs->ss = __USER_DS; | ||
467 | 463 | ||
468 | return 0; | 464 | return 0; |
469 | } | 465 | } |