aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2018-07-22 14:05:09 -0400
committerIngo Molnar <mingo@kernel.org>2018-07-24 04:07:36 -0400
commitb3681dd548d06deb2e1573890829dff4b15abf46 (patch)
treefb25a035c22c4f15997eab8bab5104f86d7e6b50
parentd9e6dbcf28f383bf08e6a3180972f5722e514a54 (diff)
x86/entry/64: Remove %ebx handling from error_entry/exit
error_entry and error_exit communicate the user vs. kernel status of the frame using %ebx. This is unnecessary -- the information is in regs->cs. Just use regs->cs. This makes error_entry simpler and makes error_exit more robust. It also fixes a nasty bug. Before all the Spectre nonsense, the xen_failsafe_callback entry point returned like this: ALLOC_PT_GPREGS_ON_STACK SAVE_C_REGS SAVE_EXTRA_REGS ENCODE_FRAME_POINTER jmp error_exit And it did not go through error_entry. This was bogus: RBX contained garbage, and error_exit expected a flag in RBX. Fortunately, it generally contained *nonzero* garbage, so the correct code path was used. As part of the Spectre fixes, code was added to clear RBX to mitigate certain speculation attacks. Now, depending on kernel configuration, RBX got zeroed and, when running some Wine workloads, the kernel crashes. This was introduced by: commit 3ac6d8c787b8 ("x86/entry/64: Clear registers for exceptions/interrupts, to reduce speculation attack surface") With this patch applied, RBX is no longer needed as a flag, and the problem goes away. I suspect that malicious userspace could use this bug to crash the kernel even without the offending patch applied, though. [ Historical note: I wrote this patch as a cleanup before I was aware of the bug it fixed. ] [ Note to stable maintainers: this should probably get applied to all kernels. If you're nervous about that, a more conservative fix to add xorl %ebx,%ebx; incl %ebx before the jump to error_exit should also fix the problem. ] Reported-and-tested-by: M. Vefa Bicakci <m.v.b@runbox.com> Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: stable@vger.kernel.org Cc: xen-devel@lists.xenproject.org Fixes: 3ac6d8c787b8 ("x86/entry/64: Clear registers for exceptions/interrupts, to reduce speculation attack surface") Link: http://lkml.kernel.org/r/b5010a090d3586b2d6e06c7ad3ec5542d1241c45.1532282627.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/entry/entry_64.S18
1 files changed, 4 insertions, 14 deletions
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 73a522d53b53..8ae7ffda8f98 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -981,7 +981,7 @@ ENTRY(\sym)
981 981
982 call \do_sym 982 call \do_sym
983 983
984 jmp error_exit /* %ebx: no swapgs flag */ 984 jmp error_exit
985 .endif 985 .endif
986END(\sym) 986END(\sym)
987.endm 987.endm
@@ -1222,7 +1222,6 @@ END(paranoid_exit)
1222 1222
1223/* 1223/*
1224 * Save all registers in pt_regs, and switch GS if needed. 1224 * Save all registers in pt_regs, and switch GS if needed.
1225 * Return: EBX=0: came from user mode; EBX=1: otherwise
1226 */ 1225 */
1227ENTRY(error_entry) 1226ENTRY(error_entry)
1228 UNWIND_HINT_FUNC 1227 UNWIND_HINT_FUNC
@@ -1269,7 +1268,6 @@ ENTRY(error_entry)
1269 * for these here too. 1268 * for these here too.
1270 */ 1269 */
1271.Lerror_kernelspace: 1270.Lerror_kernelspace:
1272 incl %ebx
1273 leaq native_irq_return_iret(%rip), %rcx 1271 leaq native_irq_return_iret(%rip), %rcx
1274 cmpq %rcx, RIP+8(%rsp) 1272 cmpq %rcx, RIP+8(%rsp)
1275 je .Lerror_bad_iret 1273 je .Lerror_bad_iret
@@ -1303,28 +1301,20 @@ ENTRY(error_entry)
1303 1301
1304 /* 1302 /*
1305 * Pretend that the exception came from user mode: set up pt_regs 1303 * Pretend that the exception came from user mode: set up pt_regs
1306 * as if we faulted immediately after IRET and clear EBX so that 1304 * as if we faulted immediately after IRET.
1307 * error_exit knows that we will be returning to user mode.
1308 */ 1305 */
1309 mov %rsp, %rdi 1306 mov %rsp, %rdi
1310 call fixup_bad_iret 1307 call fixup_bad_iret
1311 mov %rax, %rsp 1308 mov %rax, %rsp
1312 decl %ebx
1313 jmp .Lerror_entry_from_usermode_after_swapgs 1309 jmp .Lerror_entry_from_usermode_after_swapgs
1314END(error_entry) 1310END(error_entry)
1315 1311
1316
1317/*
1318 * On entry, EBX is a "return to kernel mode" flag:
1319 * 1: already in kernel mode, don't need SWAPGS
1320 * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
1321 */
1322ENTRY(error_exit) 1312ENTRY(error_exit)
1323 UNWIND_HINT_REGS 1313 UNWIND_HINT_REGS
1324 DISABLE_INTERRUPTS(CLBR_ANY) 1314 DISABLE_INTERRUPTS(CLBR_ANY)
1325 TRACE_IRQS_OFF 1315 TRACE_IRQS_OFF
1326 testl %ebx, %ebx 1316 testb $3, CS(%rsp)
1327 jnz retint_kernel 1317 jz retint_kernel
1328 jmp retint_user 1318 jmp retint_user
1329END(error_exit) 1319END(error_exit)
1330 1320