| From b3681dd548d06deb2e1573890829dff4b15abf46 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@kernel.org> |
| Date: Sun, 22 Jul 2018 11:05:09 -0700 |
| Subject: x86/entry/64: Remove %ebx handling from error_entry/exit |
| |
| From: Andy Lutomirski <luto@kernel.org> |
| |
| commit b3681dd548d06deb2e1573890829dff4b15abf46 upstream. |
| |
| 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> |
| Signed-off-by: Sarah Newman <srn@prgmr.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/entry/entry_64.S | 20 ++++---------------- |
| 1 file changed, 4 insertions(+), 16 deletions(-) |
| |
| --- a/arch/x86/entry/entry_64.S |
| +++ b/arch/x86/entry/entry_64.S |
| @@ -774,7 +774,7 @@ ENTRY(\sym) |
| |
| call \do_sym |
| |
| - jmp error_exit /* %ebx: no swapgs flag */ |
| + jmp error_exit |
| .endif |
| END(\sym) |
| .endm |
| @@ -1043,7 +1043,6 @@ END(paranoid_exit) |
| |
| /* |
| * Save all registers in pt_regs, and switch gs if needed. |
| - * Return: EBX=0: came from user mode; EBX=1: otherwise |
| */ |
| ENTRY(error_entry) |
| cld |
| @@ -1056,7 +1055,6 @@ ENTRY(error_entry) |
| * the kernel CR3 here. |
| */ |
| SWITCH_KERNEL_CR3 |
| - xorl %ebx, %ebx |
| testb $3, CS+8(%rsp) |
| jz .Lerror_kernelspace |
| |
| @@ -1087,7 +1085,6 @@ ENTRY(error_entry) |
| * for these here too. |
| */ |
| .Lerror_kernelspace: |
| - incl %ebx |
| leaq native_irq_return_iret(%rip), %rcx |
| cmpq %rcx, RIP+8(%rsp) |
| je .Lerror_bad_iret |
| @@ -1119,28 +1116,19 @@ ENTRY(error_entry) |
| |
| /* |
| * Pretend that the exception came from user mode: set up pt_regs |
| - * as if we faulted immediately after IRET and clear EBX so that |
| - * error_exit knows that we will be returning to user mode. |
| + * as if we faulted immediately after IRET. |
| */ |
| mov %rsp, %rdi |
| call fixup_bad_iret |
| mov %rax, %rsp |
| - decl %ebx |
| jmp .Lerror_entry_from_usermode_after_swapgs |
| END(error_entry) |
| |
| - |
| -/* |
| - * On entry, EBX is a "return to kernel mode" flag: |
| - * 1: already in kernel mode, don't need SWAPGS |
| - * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode |
| - */ |
| ENTRY(error_exit) |
| - movl %ebx, %eax |
| DISABLE_INTERRUPTS(CLBR_NONE) |
| TRACE_IRQS_OFF |
| - testl %eax, %eax |
| - jnz retint_kernel |
| + testb $3, CS(%rsp) |
| + jz retint_kernel |
| jmp retint_user |
| END(error_exit) |
| |