| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- From 271bc7d0577bef9f344187eb45ba8682eed242f9 Mon Sep 17 00:00:00 2001
- From: Andy Lutomirski <[email protected]>
- Date: Thu, 2 Nov 2017 00:59:00 -0700
- Subject: [PATCH 088/242] x86/entry/64: Move SWAPGS into the common
- IRET-to-usermode path
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- CVE-2017-5754
- All of the code paths that ended up doing IRET to usermode did
- SWAPGS immediately beforehand. Move the SWAPGS into the common
- code.
- Signed-off-by: Andy Lutomirski <[email protected]>
- Cc: Borislav Petkov <[email protected]>
- Cc: Brian Gerst <[email protected]>
- Cc: Dave Hansen <[email protected]>
- Cc: Linus Torvalds <[email protected]>
- Cc: Peter Zijlstra <[email protected]>
- Cc: Thomas Gleixner <[email protected]>
- Link: http://lkml.kernel.org/r/27fd6f45b7cd640de38fb9066fd0349bcd11f8e1.1509609304.git.luto@kernel.org
- Signed-off-by: Ingo Molnar <[email protected]>
- (cherry picked from commit 8a055d7f411d41755ce30db5bb65b154777c4b78)
- Signed-off-by: Andy Whitcroft <[email protected]>
- Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
- (cherry picked from commit 62a85594f9be3baeb2495089f1c2980bc497d03b)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- arch/x86/entry/entry_64.S | 32 ++++++++++++++------------------
- arch/x86/entry/entry_64_compat.S | 3 +--
- 2 files changed, 15 insertions(+), 20 deletions(-)
- diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
- index e546441fbec3..7c8258e3ad2d 100644
- --- a/arch/x86/entry/entry_64.S
- +++ b/arch/x86/entry/entry_64.S
- @@ -249,12 +249,14 @@ return_from_SYSCALL_64:
-
- /*
- * Try to use SYSRET instead of IRET if we're returning to
- - * a completely clean 64-bit userspace context.
- + * a completely clean 64-bit userspace context. If we're not,
- + * go to the slow exit path.
- */
- movq RCX(%rsp), %rcx
- movq RIP(%rsp), %r11
- - cmpq %rcx, %r11 /* RCX == RIP */
- - jne opportunistic_sysret_failed
- +
- + cmpq %rcx, %r11 /* SYSRET requires RCX == RIP */
- + jne swapgs_restore_regs_and_return_to_usermode
-
- /*
- * On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
- @@ -272,14 +274,14 @@ return_from_SYSCALL_64:
-
- /* If this changed %rcx, it was not canonical */
- cmpq %rcx, %r11
- - jne opportunistic_sysret_failed
- + jne swapgs_restore_regs_and_return_to_usermode
-
- cmpq $__USER_CS, CS(%rsp) /* CS must match SYSRET */
- - jne opportunistic_sysret_failed
- + jne swapgs_restore_regs_and_return_to_usermode
-
- movq R11(%rsp), %r11
- cmpq %r11, EFLAGS(%rsp) /* R11 == RFLAGS */
- - jne opportunistic_sysret_failed
- + jne swapgs_restore_regs_and_return_to_usermode
-
- /*
- * SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot
- @@ -300,12 +302,12 @@ return_from_SYSCALL_64:
- * would never get past 'stuck_here'.
- */
- testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
- - jnz opportunistic_sysret_failed
- + jnz swapgs_restore_regs_and_return_to_usermode
-
- /* nothing to check for RSP */
-
- cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */
- - jne opportunistic_sysret_failed
- + jne swapgs_restore_regs_and_return_to_usermode
-
- /*
- * We win! This label is here just for ease of understanding
- @@ -318,10 +320,6 @@ syscall_return_via_sysret:
- movq RSP(%rsp), %rsp
- UNWIND_HINT_EMPTY
- USERGS_SYSRET64
- -
- -opportunistic_sysret_failed:
- - SWAPGS
- - jmp restore_regs_and_return_to_usermode
- END(entry_SYSCALL_64)
-
- ENTRY(stub_ptregs_64)
- @@ -422,8 +420,7 @@ ENTRY(ret_from_fork)
- movq %rsp, %rdi
- call syscall_return_slowpath /* returns with IRQs disabled */
- TRACE_IRQS_ON /* user mode is traced as IRQS on */
- - SWAPGS
- - jmp restore_regs_and_return_to_usermode
- + jmp swapgs_restore_regs_and_return_to_usermode
-
- 1:
- /* kernel thread */
- @@ -611,9 +608,8 @@ GLOBAL(retint_user)
- mov %rsp,%rdi
- call prepare_exit_to_usermode
- TRACE_IRQS_IRETQ
- - SWAPGS
-
- -GLOBAL(restore_regs_and_return_to_usermode)
- +GLOBAL(swapgs_restore_regs_and_return_to_usermode)
- #ifdef CONFIG_DEBUG_ENTRY
- /* Assert that pt_regs indicates user mode. */
- testl $3, CS(%rsp)
- @@ -621,6 +617,7 @@ GLOBAL(restore_regs_and_return_to_usermode)
- ud2
- 1:
- #endif
- + SWAPGS
- RESTORE_EXTRA_REGS
- RESTORE_C_REGS
- REMOVE_PT_GPREGS_FROM_STACK 8
- @@ -1355,8 +1352,7 @@ ENTRY(nmi)
- * Return back to user mode. We must *not* do the normal exit
- * work, because we don't want to enable interrupts.
- */
- - SWAPGS
- - jmp restore_regs_and_return_to_usermode
- + jmp swapgs_restore_regs_and_return_to_usermode
-
- .Lnmi_from_kernel:
- /*
- diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
- index 2b3a88feaa2b..be745b7a3e3e 100644
- --- a/arch/x86/entry/entry_64_compat.S
- +++ b/arch/x86/entry/entry_64_compat.S
- @@ -336,8 +336,7 @@ ENTRY(entry_INT80_compat)
-
- /* Go back to user mode. */
- TRACE_IRQS_ON
- - SWAPGS
- - jmp restore_regs_and_return_to_usermode
- + jmp swapgs_restore_regs_and_return_to_usermode
- END(entry_INT80_compat)
-
- ALIGN
- --
- 2.14.2
|