diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-08-13 11:25:20 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-08-13 15:42:22 -0400 |
| commit | ed596cde9425509ec6ce88e19f03e9b13b6f518b (patch) | |
| tree | 9f2edfb343e60ca24c1af548681fa071fbcd2ebb | |
| parent | 26b552e0a85ba7e74d384a9624d83118d38071f7 (diff) | |
Revert x86 sigcontext cleanups
This reverts commits 9a036b93a344 ("x86/signal/64: Remove 'fs' and 'gs'
from sigcontext") and c6f2062935c8 ("x86/signal/64: Fix SS handling for
signals delivered to 64-bit programs").
They were cleanups, but they break dosemu by changing the signal return
behavior (and removing 'fs' and 'gs' from the sigcontext struct - while
not actually changing any behavior - causes build problems).
Reported-and-tested-by: Stas Sergeev <stsp@list.ru>
Acked-by: Andy Lutomirski <luto@amacapital.net>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/x86/include/asm/sigcontext.h | 6 | ||||
| -rw-r--r-- | arch/x86/include/uapi/asm/sigcontext.h | 21 | ||||
| -rw-r--r-- | arch/x86/kernel/signal.c | 26 |
3 files changed, 17 insertions, 36 deletions
diff --git a/arch/x86/include/asm/sigcontext.h b/arch/x86/include/asm/sigcontext.h index 6fe6b182c998..9dfce4e0417d 100644 --- a/arch/x86/include/asm/sigcontext.h +++ b/arch/x86/include/asm/sigcontext.h | |||
| @@ -57,9 +57,9 @@ struct sigcontext { | |||
| 57 | unsigned long ip; | 57 | unsigned long ip; |
| 58 | unsigned long flags; | 58 | unsigned long flags; |
| 59 | unsigned short cs; | 59 | unsigned short cs; |
| 60 | unsigned short __pad2; /* Was called gs, but was always zero. */ | 60 | unsigned short gs; |
| 61 | unsigned short __pad1; /* Was called fs, but was always zero. */ | 61 | unsigned short fs; |
| 62 | unsigned short ss; | 62 | unsigned short __pad0; |
| 63 | unsigned long err; | 63 | unsigned long err; |
| 64 | unsigned long trapno; | 64 | unsigned long trapno; |
| 65 | unsigned long oldmask; | 65 | unsigned long oldmask; |
diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi/asm/sigcontext.h index 0e8a973de9ee..40836a9a7250 100644 --- a/arch/x86/include/uapi/asm/sigcontext.h +++ b/arch/x86/include/uapi/asm/sigcontext.h | |||
| @@ -177,24 +177,9 @@ struct sigcontext { | |||
| 177 | __u64 rip; | 177 | __u64 rip; |
| 178 | __u64 eflags; /* RFLAGS */ | 178 | __u64 eflags; /* RFLAGS */ |
| 179 | __u16 cs; | 179 | __u16 cs; |
| 180 | 180 | __u16 gs; | |
| 181 | /* | 181 | __u16 fs; |
| 182 | * Prior to 2.5.64 ("[PATCH] x86-64 updates for 2.5.64-bk3"), | 182 | __u16 __pad0; |
| 183 | * Linux saved and restored fs and gs in these slots. This | ||
| 184 | * was counterproductive, as fsbase and gsbase were never | ||
| 185 | * saved, so arch_prctl was presumably unreliable. | ||
| 186 | * | ||
| 187 | * If these slots are ever needed for any other purpose, there | ||
| 188 | * is some risk that very old 64-bit binaries could get | ||
| 189 | * confused. I doubt that many such binaries still work, | ||
| 190 | * though, since the same patch in 2.5.64 also removed the | ||
| 191 | * 64-bit set_thread_area syscall, so it appears that there is | ||
| 192 | * no TLS API that works in both pre- and post-2.5.64 kernels. | ||
| 193 | */ | ||
| 194 | __u16 __pad2; /* Was gs. */ | ||
| 195 | __u16 __pad1; /* Was fs. */ | ||
| 196 | |||
| 197 | __u16 ss; | ||
| 198 | __u64 err; | 183 | __u64 err; |
| 199 | __u64 trapno; | 184 | __u64 trapno; |
| 200 | __u64 oldmask; | 185 | __u64 oldmask; |
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 | } |
