Borislav Petkov b64e2f
From: Peter Zijlstra <peterz@infradead.org>
Borislav Petkov b64e2f
Date: Tue, 14 Jun 2022 23:16:02 +0200
Borislav Petkov b64e2f
Subject: x86/bugs: Add retbleed=ibpb
Borislav Petkov b64e2f
Git-commit: 3ebc170068885b6fc7bedda6c667bb2c4d533159
Borislav Petkov d06c64
Patch-mainline: v5.19-rc4
Borislav Petkov b64e2f
References: bsc#1199657 CVE-2022-29900 CVE-2022-29901
Borislav Petkov b64e2f
Borislav Petkov b64e2f
jmp2ret mitigates the easy-to-attack case at relatively low overhead.
Borislav Petkov b64e2f
It mitigates the long speculation windows after a mispredicted RET, but
Borislav Petkov b64e2f
it does not mitigate the short speculation window from arbitrary
Borislav Petkov b64e2f
instruction boundaries.
Borislav Petkov b64e2f
Borislav Petkov b64e2f
On Zen2, there is a chicken bit which needs setting, which mitigates
Borislav Petkov b64e2f
"arbitrary instruction boundaries" down to just "basic block boundaries".
Borislav Petkov b64e2f
Borislav Petkov b64e2f
But there is no fix for the short speculation window on basic block
Borislav Petkov b64e2f
boundaries, other than to flush the entire BTB to evict all attacker
Borislav Petkov b64e2f
predictions.
Borislav Petkov b64e2f
Borislav Petkov b64e2f
On the spectrum of "fast & blurry" -> "safe", there is (on top of STIBP
Borislav Petkov b64e2f
or no-SMT):
Borislav Petkov b64e2f
Borislav Petkov b64e2f
  1) Nothing		System wide open
Borislav Petkov b64e2f
  2) jmp2ret		May stop a script kiddy
Borislav Petkov b64e2f
  3) jmp2ret+chickenbit  Raises the bar rather further
Borislav Petkov b64e2f
  4) IBPB		Only thing which can count as "safe".
Borislav Petkov b64e2f
Borislav Petkov b64e2f
Tentative numbers put IBPB-on-entry at a 2.5x hit on Zen2, and a 10x hit
Borislav Petkov b64e2f
on Zen1 according to lmbench.
Borislav Petkov b64e2f
Borislav Petkov b64e2f
  [ bp: Fixup feature bit comments, document option, 32-bit build fix. ]
Borislav Petkov b64e2f
Borislav Petkov b64e2f
Suggested-by: Andrew Cooper <Andrew.Cooper3@citrix.com>
Borislav Petkov b64e2f
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Borislav Petkov b64e2f
Signed-off-by: Borislav Petkov <bp@suse.de>
Borislav Petkov b64e2f
Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org>
Borislav Petkov b64e2f
Signed-off-by: Borislav Petkov <bp@suse.de>
Borislav Petkov b64e2f
---
Borislav Petkov b64e2f
 Documentation/admin-guide/kernel-parameters.txt |    3 +
Borislav Petkov b64e2f
 arch/x86/entry/Makefile                         |    2 -
Borislav Petkov b64e2f
 arch/x86/entry/entry.S                          |   32 +++++++++++++++++
Borislav Petkov b64e2f
 arch/x86/include/asm/cpufeatures.h              |    2 -
Borislav Petkov b64e2f
 arch/x86/include/asm/nospec-branch.h            |    8 +++-
Borislav Petkov b64e2f
 arch/x86/kernel/cpu/bugs.c                      |   43 ++++++++++++++++++------
Borislav Petkov b64e2f
 6 files changed, 77 insertions(+), 13 deletions(-)
Borislav Petkov b64e2f
Borislav Petkov b64e2f
--- /dev/null
Borislav Petkov b64e2f
+++ b/arch/x86/entry/entry.S
Borislav Petkov b64e2f
@@ -0,0 +1,32 @@
Borislav Petkov b64e2f
+/* SPDX-License-Identifier: GPL-2.0 */
Borislav Petkov b64e2f
+/*
Borislav Petkov b64e2f
+ * Common place for both 32- and 64-bit entry routines.
Borislav Petkov b64e2f
+ */
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+#include <linux/linkage.h>
Borislav Petkov b64e2f
+#include <asm/export.h>
Borislav Petkov b64e2f
+#include <asm/msr-index.h>
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+.pushsection .noinstr.text, "ax"
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+ENTRY(entry_ibpb)
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+	push %rax
Borislav Petkov b64e2f
+	push %rcx
Borislav Petkov b64e2f
+	push %rdx
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+	movl	$MSR_IA32_PRED_CMD, %ecx
Borislav Petkov b64e2f
+	movl	$PRED_CMD_IBPB, %eax
Borislav Petkov b64e2f
+	xorl	%edx, %edx
Borislav Petkov b64e2f
+	wrmsr
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+	pop %rdx
Borislav Petkov b64e2f
+	pop %rcx
Borislav Petkov b64e2f
+	pop %rax
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+	RET
Borislav Petkov b64e2f
+END(entry_ibpb)
Borislav Petkov b64e2f
+/* For KVM */
Borislav Petkov b64e2f
+EXPORT_SYMBOL_GPL(entry_ibpb);
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+.popsection
Borislav Petkov b64e2f
--- a/arch/x86/entry/Makefile
Borislav Petkov b64e2f
+++ b/arch/x86/entry/Makefile
Borislav Petkov b64e2f
@@ -6,7 +6,7 @@ OBJECT_FILES_NON_STANDARD_entry_64_compa
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 CFLAGS_syscall_64.o		+= $(call cc-option,-Wno-override-init,)
Borislav Petkov b64e2f
 CFLAGS_syscall_32.o		+= $(call cc-option,-Wno-override-init,)
Borislav Petkov b64e2f
-obj-y				:= entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
Borislav Petkov b64e2f
+obj-y				:= entry.o entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
Borislav Petkov b64e2f
 obj-y				+= common.o
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 obj-y				+= vdso/
Borislav Petkov b64e2f
--- a/arch/x86/include/asm/cpufeatures.h
Borislav Petkov b64e2f
+++ b/arch/x86/include/asm/cpufeatures.h
Borislav Petkov b64e2f
@@ -283,7 +283,7 @@
Borislav Petkov b64e2f
 #define X86_FEATURE_CQM_MBM_LOCAL	(11*32+ 3) /* LLC Local MBM monitoring */
Borislav Petkov b64e2f
 #define X86_FEATURE_FENCE_SWAPGS_USER	(11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
Borislav Petkov b64e2f
 #define X86_FEATURE_FENCE_SWAPGS_KERNEL	(11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
Borislav Petkov b64e2f
-/* FREE!				(11*32+10) */
Borislav Petkov b64e2f
+#define X86_FEATURE_ENTRY_IBPB		(11*32+10) /* "" Issue an IBPB on kernel entry */
Borislav Petkov b64e2f
 /* FREE!				(11*32+11) */
Borislav Petkov b64e2f
 #define X86_FEATURE_RETPOLINE		(11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
Borislav Petkov b64e2f
 #define X86_FEATURE_RETPOLINE_LFENCE	(11*32+13) /* "" Use LFENCE for Spectre variant 2 */
Borislav Petkov b64e2f
--- a/arch/x86/include/asm/nospec-branch.h
Borislav Petkov b64e2f
+++ b/arch/x86/include/asm/nospec-branch.h
Borislav Petkov b64e2f
@@ -155,14 +155,17 @@
Borislav Petkov b64e2f
  * return thunk isn't mapped into the userspace tables (then again, AMD
Borislav Petkov b64e2f
  * typically has NO_MELTDOWN).
Borislav Petkov b64e2f
  *
Borislav Petkov b64e2f
- * Doesn't clobber any registers but does require a stable stack.
Borislav Petkov b64e2f
+ * While zen_untrain_ret() doesn't clobber anything but requires stack,
Borislav Petkov b64e2f
+ * entry_ibpb() will clobber AX, CX, DX.
Borislav Petkov b64e2f
  *
Borislav Petkov b64e2f
  * As such, this must be placed after every *SWITCH_TO_KERNEL_CR3 at a point
Borislav Petkov b64e2f
  * where we have a stack but before any RET instruction.
Borislav Petkov b64e2f
  */
Borislav Petkov b64e2f
 .macro UNTRAIN_RET
Borislav Petkov b64e2f
 #ifdef CONFIG_RETPOLINE
Borislav Petkov b64e2f
-	ALTERNATIVE "", "call zen_untrain_ret", X86_FEATURE_UNRET
Borislav Petkov b64e2f
+	ALTERNATIVE_2 "",						\
Borislav Petkov b64e2f
+	              "call zen_untrain_ret", X86_FEATURE_UNRET,	\
Borislav Petkov b64e2f
+		      "call entry_ibpb", X86_FEATURE_ENTRY_IBPB
Borislav Petkov b64e2f
 #endif
Borislav Petkov b64e2f
 .endm
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
@@ -185,6 +188,7 @@
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 extern void __x86_return_thunk(void);
Borislav Petkov b64e2f
 extern void zen_untrain_ret(void);
Borislav Petkov b64e2f
+extern void entry_ibpb(void);
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 /*
Borislav Petkov b64e2f
  * Inline asm uses the %V modifier which is only in newer GCC
Borislav Petkov b64e2f
--- a/arch/x86/kernel/cpu/bugs.c
Borislav Petkov b64e2f
+++ b/arch/x86/kernel/cpu/bugs.c
Borislav Petkov b64e2f
@@ -878,6 +878,7 @@ static enum spectre_v2_mitigation spectr
Borislav Petkov b64e2f
 enum retbleed_mitigation {
Borislav Petkov b64e2f
 	RETBLEED_MITIGATION_NONE,
Borislav Petkov b64e2f
 	RETBLEED_MITIGATION_UNRET,
Borislav Petkov b64e2f
+	RETBLEED_MITIGATION_IBPB,
Borislav Petkov b64e2f
 	RETBLEED_MITIGATION_IBRS,
Borislav Petkov b64e2f
 	RETBLEED_MITIGATION_EIBRS,
Borislav Petkov b64e2f
 };
Borislav Petkov b64e2f
@@ -886,11 +887,13 @@ enum retbleed_mitigation_cmd {
Borislav Petkov b64e2f
 	RETBLEED_CMD_OFF,
Borislav Petkov b64e2f
 	RETBLEED_CMD_AUTO,
Borislav Petkov b64e2f
 	RETBLEED_CMD_UNRET,
Borislav Petkov b64e2f
+	RETBLEED_CMD_IBPB,
Borislav Petkov b64e2f
 };
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 const char * const retbleed_strings[] = {
Borislav Petkov b64e2f
 	[RETBLEED_MITIGATION_NONE]	= "Vulnerable",
Borislav Petkov b64e2f
 	[RETBLEED_MITIGATION_UNRET]	= "Mitigation: untrained return thunk",
Borislav Petkov b64e2f
+	[RETBLEED_MITIGATION_IBPB]	= "Mitigation: IBPB",
Borislav Petkov b64e2f
 	[RETBLEED_MITIGATION_IBRS]	= "Mitigation: IBRS",
Borislav Petkov b64e2f
 	[RETBLEED_MITIGATION_EIBRS]	= "Mitigation: Enhanced IBRS",
Borislav Petkov b64e2f
 };
Borislav Petkov b64e2f
@@ -920,6 +923,8 @@ static int __init retbleed_parse_cmdline
Borislav Petkov b64e2f
 			retbleed_cmd = RETBLEED_CMD_AUTO;
Borislav Petkov b64e2f
 		} else if (!strcmp(str, "unret")) {
Borislav Petkov b64e2f
 			retbleed_cmd = RETBLEED_CMD_UNRET;
Borislav Petkov b64e2f
+		} else if (!strcmp(str, "ibpb")) {
Borislav Petkov b64e2f
+			retbleed_cmd = RETBLEED_CMD_IBPB;
Borislav Petkov b64e2f
 		} else if (!strcmp(str, "nosmt")) {
Borislav Petkov b64e2f
 			retbleed_nosmt = true;
Borislav Petkov b64e2f
 		} else {
Borislav Petkov b64e2f
@@ -934,11 +939,13 @@ static int __init retbleed_parse_cmdline
Borislav Petkov b64e2f
 early_param("retbleed", retbleed_parse_cmdline);
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 #define RETBLEED_UNTRAIN_MSG "WARNING: BTB untrained return thunk mitigation is only effective on AMD/Hygon!\n"
Borislav Petkov b64e2f
-#define RETBLEED_COMPILER_MSG "WARNING: kernel not compiled with RETPOLINE or -mfunction-return capable compiler!\n"
Borislav Petkov b64e2f
+#define RETBLEED_COMPILER_MSG "WARNING: kernel not compiled with RETPOLINE or -mfunction-return capable compiler; falling back to IBPB!\n"
Borislav Petkov b64e2f
 #define RETBLEED_INTEL_MSG "WARNING: Spectre v2 mitigation leaves CPU vulnerable to RETBleed attacks, data leaks possible!\n"
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 static void __init retbleed_select_mitigation(void)
Borislav Petkov b64e2f
 {
Borislav Petkov b64e2f
+	bool mitigate_smt = false;
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
 	if (!boot_cpu_has_bug(X86_BUG_RETBLEED))
Borislav Petkov b64e2f
 		return;
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
@@ -950,11 +957,21 @@ static void __init retbleed_select_mitig
Borislav Petkov b64e2f
 		retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
Borislav Petkov b64e2f
 		break;
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
+	case RETBLEED_CMD_IBPB:
Borislav Petkov b64e2f
+		retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
Borislav Petkov b64e2f
+		break;
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
 	case RETBLEED_CMD_AUTO:
Borislav Petkov b64e2f
 	default:
Borislav Petkov b64e2f
 		if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
Borislav Petkov b64e2f
-		    boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
Borislav Petkov b64e2f
-			retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
Borislav Petkov b64e2f
+		    boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+			if (IS_ENABLED(CONFIG_RETPOLINE) &&
Borislav Petkov b64e2f
+			    IS_ENABLED(CONFIG_CC_HAS_RETURN_THUNK))
Borislav Petkov b64e2f
+				retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
Borislav Petkov b64e2f
+			else
Borislav Petkov b64e2f
+				retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
Borislav Petkov b64e2f
+		}
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 		/*
Borislav Petkov b64e2f
 		 * The Intel mitigation (IBRS) was already selected in
Borislav Petkov b64e2f
@@ -970,26 +987,34 @@ static void __init retbleed_select_mitig
Borislav Petkov b64e2f
 		if (!IS_ENABLED(CONFIG_RETPOLINE) ||
Borislav Petkov b64e2f
 		    !IS_ENABLED(CONFIG_CC_HAS_RETURN_THUNK)) {
Borislav Petkov b64e2f
 			pr_err(RETBLEED_COMPILER_MSG);
Borislav Petkov b64e2f
-			retbleed_mitigation = RETBLEED_MITIGATION_NONE;
Borislav Petkov b64e2f
-			break;
Borislav Petkov b64e2f
+			retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
Borislav Petkov b64e2f
+			goto retbleed_force_ibpb;
Borislav Petkov b64e2f
 		}
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 		setup_force_cpu_cap(X86_FEATURE_RETHUNK);
Borislav Petkov b64e2f
 		setup_force_cpu_cap(X86_FEATURE_UNRET);
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
-		if (!boot_cpu_has(X86_FEATURE_STIBP) &&
Borislav Petkov b64e2f
-		    (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
Borislav Petkov b64e2f
-			cpu_smt_disable(false);
Borislav Petkov b64e2f
-
Borislav Petkov b64e2f
 		if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
Borislav Petkov b64e2f
 		    boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
Borislav Petkov b64e2f
 			pr_err(RETBLEED_UNTRAIN_MSG);
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+		mitigate_smt = true;
Borislav Petkov b64e2f
+		break;
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
+	case RETBLEED_MITIGATION_IBPB:
Borislav Petkov b64e2f
+retbleed_force_ibpb:
Borislav Petkov b64e2f
+		setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
Borislav Petkov b64e2f
+		mitigate_smt = true;
Borislav Petkov b64e2f
 		break;
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
 	default:
Borislav Petkov b64e2f
 		break;
Borislav Petkov b64e2f
 	}
Borislav Petkov b64e2f
 
Borislav Petkov b64e2f
+	if (mitigate_smt && !boot_cpu_has(X86_FEATURE_STIBP) &&
Borislav Petkov b64e2f
+	    (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
Borislav Petkov b64e2f
+		cpu_smt_disable(false);
Borislav Petkov b64e2f
+
Borislav Petkov b64e2f
 	/*
Borislav Petkov b64e2f
 	 * Let IBRS trump all on Intel without affecting the effects of the
Borislav Petkov b64e2f
 	 * retbleed= cmdline option.
Borislav Petkov b64e2f
--- a/Documentation/admin-guide/kernel-parameters.txt
Borislav Petkov b64e2f
+++ b/Documentation/admin-guide/kernel-parameters.txt
Borislav Petkov b64e2f
@@ -3986,6 +3986,9 @@
Borislav Petkov b64e2f
 				       disabling SMT if necessary for
Borislav Petkov b64e2f
 				       the full mitigation (only on Zen1
Borislav Petkov b64e2f
 				       and older without STIBP).
Borislav Petkov b64e2f
+			ibpb	     - mitigate short speculation windows on
Borislav Petkov b64e2f
+				       basic block boundaries too. Safe, highest
Borislav Petkov b64e2f
+				       perf impact.
Borislav Petkov b64e2f
 			unret        - force enable untrained return thunks,
Borislav Petkov b64e2f
 				       only effective on AMD f15h-f17h
Borislav Petkov b64e2f
 				       based systems.