Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3111fae authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Greg Kroah-Hartman
Browse files

x86/entry: Add kernel IBRS implementation



commit 2dbb887e875b1de3ca8f40ddf26bcfe55798c609 upstream.

Implement Kernel IBRS - currently the only known option to mitigate RSB
underflow speculation issues on Skylake hardware.

Note: since IBRS_ENTER requires fuller context established than
UNTRAIN_RET, it must be placed after it. However, since UNTRAIN_RET
itself implies a RET, it must come after IBRS_ENTER. This means
IBRS_ENTER needs to also move UNTRAIN_RET.

Note 2: KERNEL_IBRS is sub-optimal for XenPV.

Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarJosh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
[cascardo: conflict at arch/x86/entry/entry_64.S, skip_r11rcx]
[cascardo: conflict at arch/x86/entry/entry_64_compat.S]
[cascardo: conflict fixups, no ANNOTATE_NOENDBR]
[cascardo: entry fixups because of missing UNTRAIN_RET]
[cascardo: conflicts on fsgsbase]
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fd32a315
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@
#include <asm/percpu.h>
#include <asm/asm-offsets.h>
#include <asm/processor-flags.h>
#include <asm/msr.h>
#include <asm/nospec-branch.h>

/*

@@ -308,6 +310,62 @@ For 32-bit we have the following conventions - kernel is built with

#endif

/*
 * IBRS kernel mitigation for Spectre_v2.
 *
 * Assumes full context is established (PUSH_REGS, CR3 and GS) and it clobbers
 * the regs it uses (AX, CX, DX). Must be called before the first RET
 * instruction (NOTE! UNTRAIN_RET includes a RET instruction)
 *
 * The optional argument is used to save/restore the current value,
 * which is used on the paranoid paths.
 *
 * Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
 */
.macro IBRS_ENTER save_reg
	ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
	movl	$MSR_IA32_SPEC_CTRL, %ecx

.ifnb \save_reg
	rdmsr
	shl	$32, %rdx
	or	%rdx, %rax
	mov	%rax, \save_reg
	test	$SPEC_CTRL_IBRS, %eax
	jz	.Ldo_wrmsr_\@
	lfence
	jmp	.Lend_\@
.Ldo_wrmsr_\@:
.endif

	movq	PER_CPU_VAR(x86_spec_ctrl_current), %rdx
	movl	%edx, %eax
	shr	$32, %rdx
	wrmsr
.Lend_\@:
.endm

/*
 * Similar to IBRS_ENTER, requires KERNEL GS,CR3 and clobbers (AX, CX, DX)
 * regs. Must be called after the last RET.
 */
.macro IBRS_EXIT save_reg
	ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
	movl	$MSR_IA32_SPEC_CTRL, %ecx

.ifnb \save_reg
	mov	\save_reg, %rdx
.else
	movq	PER_CPU_VAR(x86_spec_ctrl_current), %rdx
	andl	$(~SPEC_CTRL_IBRS), %edx
.endif

	movl	%edx, %eax
	shr	$32, %rdx
	wrmsr
.Lend_\@:
.endm

/*
 * Mitigate Spectre v1 for conditional swapgs code paths.
 *
+28 −1
Original line number Diff line number Diff line
@@ -172,6 +172,10 @@ GLOBAL(entry_SYSCALL_64_after_hwframe)
	/* IRQs are off. */
	movq	%rax, %rdi
	movq	%rsp, %rsi

	/* clobbers %rax, make sure it is after saving the syscall nr */
	IBRS_ENTER

	call	do_syscall_64		/* returns with IRQs disabled */

	TRACE_IRQS_IRETQ		/* we're about to change IF */
@@ -248,6 +252,7 @@ GLOBAL(entry_SYSCALL_64_after_hwframe)
	 * perf profiles. Nothing jumps here.
	 */
syscall_return_via_sysret:
	IBRS_EXIT
	POP_REGS pop_rdi=0

	/*
@@ -621,6 +626,7 @@ GLOBAL(retint_user)
	TRACE_IRQS_IRETQ

GLOBAL(swapgs_restore_regs_and_return_to_usermode)
	IBRS_EXIT
#ifdef CONFIG_DEBUG_ENTRY
	/* Assert that pt_regs indicates user mode. */
	testb	$3, CS(%rsp)
@@ -1247,7 +1253,13 @@ ENTRY(paranoid_entry)
	 */
	FENCE_SWAPGS_KERNEL_ENTRY

	ret
	/*
	 * Once we have CR3 and %GS setup save and set SPEC_CTRL. Just like
	 * CR3 above, keep the old value in a callee saved register.
	 */
	IBRS_ENTER save_reg=%r15

	RET
END(paranoid_entry)

/*
@@ -1275,12 +1287,20 @@ ENTRY(paranoid_exit)
	jmp	.Lparanoid_exit_restore
.Lparanoid_exit_no_swapgs:
	TRACE_IRQS_IRETQ_DEBUG

	/*
	 * Must restore IBRS state before both CR3 and %GS since we need access
	 * to the per-CPU x86_spec_ctrl_shadow variable.
	 */
	IBRS_EXIT save_reg=%r15

	/* Always restore stashed CR3 value (see paranoid_entry) */
	RESTORE_CR3	scratch_reg=%rbx save_reg=%r14
.Lparanoid_exit_restore:
	jmp restore_regs_and_return_to_kernel
END(paranoid_exit)


/*
 * Save all registers in pt_regs, and switch GS if needed.
 */
@@ -1300,6 +1320,7 @@ ENTRY(error_entry)
	FENCE_SWAPGS_USER_ENTRY
	/* We have user CR3.  Change to kernel CR3. */
	SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
	IBRS_ENTER

.Lerror_entry_from_usermode_after_swapgs:
	/* Put us onto the real thread stack. */
@@ -1355,6 +1376,7 @@ ENTRY(error_entry)
	SWAPGS
	FENCE_SWAPGS_USER_ENTRY
	SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
	IBRS_ENTER

	/*
	 * Pretend that the exception came from user mode: set up pt_regs
@@ -1460,6 +1482,8 @@ ENTRY(nmi)
	PUSH_AND_CLEAR_REGS rdx=(%rdx)
	ENCODE_FRAME_POINTER

	IBRS_ENTER

	/*
	 * At this point we no longer need to worry about stack damage
	 * due to nesting -- we're on the normal thread stack and we're
@@ -1683,6 +1707,9 @@ end_repeat_nmi:
	movq	$-1, %rsi
	call	do_nmi

	/* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
	IBRS_EXIT save_reg=%r15

	/* Always restore stashed CR3 value (see paranoid_entry) */
	RESTORE_CR3 scratch_reg=%r15 save_reg=%r14

+10 −1
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@
 *
 * Copyright 2000-2002 Andi Kleen, SuSE Labs.
 */
#include "calling.h"
#include <asm/asm-offsets.h>
#include <asm/current.h>
#include <asm/errno.h>
@@ -17,6 +16,8 @@
#include <linux/linkage.h>
#include <linux/err.h>

#include "calling.h"

	.section .entry.text, "ax"

/*
@@ -106,6 +107,8 @@ ENTRY(entry_SYSENTER_compat)
	xorl	%r15d, %r15d		/* nospec   r15 */
	cld

	IBRS_ENTER

	/*
	 * SYSENTER doesn't filter flags, so we need to clear NT and AC
	 * ourselves.  To save a few cycles, we can check whether
@@ -253,6 +256,8 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe)
	 */
	TRACE_IRQS_OFF

	IBRS_ENTER

	movq	%rsp, %rdi
	call	do_fast_syscall_32
	/* XEN PV guests always use IRET path */
@@ -267,6 +272,9 @@ sysret32_from_system_call:
	 */
	STACKLEAK_ERASE
	TRACE_IRQS_ON			/* User mode traces as IRQs on. */

	IBRS_EXIT

	movq	RBX(%rsp), %rbx		/* pt_regs->rbx */
	movq	RBP(%rsp), %rbp		/* pt_regs->rbp */
	movq	EFLAGS(%rsp), %r11	/* pt_regs->flags (in r11) */
@@ -408,6 +416,7 @@ ENTRY(entry_INT80_compat)
	 * gate turned them off.
	 */
	TRACE_IRQS_OFF
	IBRS_ENTER

	movq	%rsp, %rdi
	call	do_int80_syscall_32
+1 −1
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@
#define X86_FEATURE_PROC_FEEDBACK	( 7*32+ 9) /* AMD ProcFeedbackInterface */
#define X86_FEATURE_SME			( 7*32+10) /* AMD Secure Memory Encryption */
#define X86_FEATURE_PTI			( 7*32+11) /* Kernel Page Table Isolation enabled */
/* FREE!				( 7*32+12) */
#define X86_FEATURE_KERNEL_IBRS		( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
/* FREE!				( 7*32+13) */
#define X86_FEATURE_INTEL_PPIN		( 7*32+14) /* Intel Processor Inventory Number */
#define X86_FEATURE_CDP_L2		( 7*32+15) /* Code and Data Prioritization L2 */