Commit 4b0c9c8a authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Kleber Sacilotto de Souza

x86/speculation: Prepare entry code for Spectre v1 swapgs mitigations

Spectre v1 isn't only about array bounds checks.  It can affect any
conditional checks.  The kernel entry code interrupt, exception, and NMI
handlers all have conditional swapgs checks.  Those may be problematic in
the context of Spectre v1, as kernel code can speculatively run with a user
GS.

For example:

	if (coming from user space)
		swapgs
	mov %gs:<percpu_offset>, %reg
	mov (%reg), %reg1

When coming from user space, the CPU can speculatively skip the swapgs, and
then do a speculative percpu load using the user GS value.  So the user can
speculatively force a read of any kernel value.  If a gadget exists which
uses the percpu value as an address in another load/store, then the
contents of the kernel value may become visible via an L1 side channel
attack.

A similar attack exists when coming from kernel space.  The CPU can
speculatively do the swapgs, causing the user GS to get used for the rest
of the speculative window.

The mitigation is similar to a traditional Spectre v1 mitigation, except:

  a) index masking isn't possible; because the index (percpu offset)
     isn't user-controlled; and

  b) an lfence is needed in both the "from user" swapgs path and the
     "from kernel" non-swapgs path (because of the two attacks described
     above).

The user entry swapgs paths already have SWITCH_TO_KERNEL_CR3, which has a
CR3 write when PTI is enabled.  Since CR3 writes are serializing, the
lfences can be skipped in those cases.

On the other hand, the kernel entry swapgs paths don't depend on PTI.

To avoid unnecessary lfences for the user entry case, create two separate
features for alternative patching:

  X86_FEATURE_FENCE_SWAPGS_USER
  X86_FEATURE_FENCE_SWAPGS_KERNEL

Use these features in entry code to patch in lfences where needed.

The features aren't enabled yet, so there's no functional change.
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarDave Hansen <dave.hansen@intel.com>

CVE-2019-1125

(backported from commit 18ec54fd)
[tyhicks: Backport to Xenial:
 - Adjust context in calling.h
 - Minor rework of fencing in entry_64.S due to differences in entry points
 - Add a FENCE_SWAPGS_KERNEL_ENTRY to a swapgs, in NMI entry path, that
   wasn't present in newer kernels
 - Indent macros in calling.h to match the rest of the file's style
 - Move include of calling.h later in entry_64.S to fix build failure]
Signed-off-by: default avatarTyler Hicks <tyhicks@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 1dc11691
......@@ -199,6 +199,23 @@ For 32-bit we have the following conventions - kernel is built with
.byte 0xf1
.endm
/*
* Mitigate Spectre v1 for conditional swapgs code paths.
*
* FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
* prevent a speculative swapgs when coming from kernel space.
*
* FENCE_SWAPGS_KERNEL_ENTRY is used in the kernel entry non-swapgs code path,
* to prevent the swapgs from getting speculatively skipped when coming from
* user space.
*/
.macro FENCE_SWAPGS_USER_ENTRY
ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_USER
.endm
.macro FENCE_SWAPGS_KERNEL_ENTRY
ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_KERNEL
.endm
#else /* CONFIG_X86_64 */
/*
......
......@@ -22,7 +22,6 @@
#include <asm/segment.h>
#include <asm/cache.h>
#include <asm/errno.h>
#include "calling.h"
#include <asm/asm-offsets.h>
#include <asm/msr.h>
#include <asm/unistd.h>
......@@ -46,6 +45,8 @@
#define __AUDIT_ARCH_64BIT 0x80000000
#define __AUDIT_ARCH_LE 0x40000000
#include "calling.h"
.code64
.section .entry.text, "ax"
......@@ -560,6 +561,7 @@ END(irq_entries_start)
* tracking that we're in kernel mode.
*/
SWAPGS
FENCE_SWAPGS_USER_ENTRY
SWITCH_KERNEL_CR3
ENABLE_IBRS
......@@ -578,7 +580,10 @@ END(irq_entries_start)
call enter_from_user_mode
#endif
jmpq 2f
1:
FENCE_SWAPGS_KERNEL_ENTRY
2:
/*
* Save previous stack pointer, optionally switch to interrupt stack.
* irq_count is used to check if a CPU is already on an interrupt stack
......@@ -1089,6 +1094,13 @@ ENTRY(paranoid_entry)
movq %rax, %cr3
2:
#endif
/*
* The above CR3 update sequence doesn't do an
* unconditional CR3 write, even in the PTI case. So do an lfence
* to prevent GS speculation, regardless of whether PTI is enabled.
*/
FENCE_SWAPGS_KERNEL_ENTRY
ENABLE_IBRS_CLOBBER
ret
......@@ -1154,6 +1166,7 @@ ENTRY(error_entry)
* from user mode due to an IRET fault.
*/
SWAPGS
FENCE_SWAPGS_USER_ENTRY
ENABLE_IBRS
......@@ -1169,6 +1182,8 @@ ENTRY(error_entry)
#endif
ret
.Lerror_entry_done_lfence:
FENCE_SWAPGS_KERNEL_ENTRY
.Lerror_entry_done:
TRACE_IRQS_OFF
ret
......@@ -1187,7 +1202,7 @@ ENTRY(error_entry)
cmpq %rax, RIP+8(%rsp)
je .Lbstep_iret
cmpq $gs_change, RIP+8(%rsp)
jne .Lerror_entry_done
jne .Lerror_entry_done_lfence
/*
* hack: gs_change can fail with user gsbase. If this happens, fix up
......@@ -1208,6 +1223,7 @@ ENTRY(error_entry)
*/
ENABLE_IBRS_CLOBBER
SWAPGS
FENCE_SWAPGS_USER_ENTRY
/*
* Pretend that the exception came from user mode: set up pt_regs
......@@ -1304,6 +1320,7 @@ ENTRY(nmi)
* to switch CR3 here.
*/
cld
FENCE_SWAPGS_USER_ENTRY
movq %rsp, %rdx
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
pushq 5*8(%rdx) /* pt_regs->ss */
......@@ -1593,6 +1610,11 @@ end_repeat_nmi:
movq %rax, %cr3
2:
#endif
/*
* The above CR3 update sequence doesn't do a CR3 write in the non-PTI
* case. So do an lfence to prevent GS speculation.
*/
FENCE_SWAPGS_KERNEL_ENTRY
/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
call do_nmi
......
......@@ -269,6 +269,8 @@
#define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* LLC occupancy monitoring */
#define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* LLC Total MBM monitoring */
#define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* LLC Local MBM monitoring */
#define X86_FEATURE_FENCE_SWAPGS_USER (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
#define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment