diff mbox series

[SRU,Trusty,2/3] UBUNTU: SAUCE: x86/speculation: Cleanup IBRS runtime control handling (v2)

Message ID 20181121173113.13474-3-juergh@canonical.com
State New
Headers show
Series Cleanups for CVE-2017-5715 (Spectre v2) | expand

Commit Message

Juerg Haefliger Nov. 21, 2018, 5:31 p.m. UTC
Cleanup the code to match Xenial. Functional changes introduced:
  - Return an error when someone tries to enable IBRS via procfs on HW that
    doesn't have IBRS support.
  - Write every IBRS state change to the kernel log.
  - Add an IBRS state entry to
    /sys/devices/system/cpu/vulnerabilities/spectre_v2.

CVE-2017-5715

Signed-off-by: Juerg Haefliger <juergh@canonical.com>
---
 arch/x86/include/asm/nospec-branch.h |  6 +++---
 arch/x86/include/asm/spec_ctrl.h     |  3 +++
 arch/x86/kernel/acpi/cstate.c        |  4 ++--
 arch/x86/kernel/cpu/bugs.c           | 24 +++++++++++----------
 arch/x86/kernel/process.c            |  6 +++---
 arch/x86/kernel/smpboot.c            |  4 ++--
 kernel/sysctl.c                      | 32 +++++++++++++++++-----------
 7 files changed, 45 insertions(+), 34 deletions(-)
diff mbox series

Patch

diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index 3cc7e65fbb3a..4049dd47a444 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -196,7 +196,7 @@  int set_ibpb_enabled(unsigned int);
 
 /* The IBRS runtime control knob */
 extern unsigned int ibrs_enabled;
-void ibrs_enable(void);
+int set_ibrs_enabled(unsigned int);
 
 /* The Spectre V2 mitigation variants */
 enum spectre_v2_mitigation {
@@ -266,7 +266,7 @@  do {									\
 	preempt_enable();						\
 } while (0)
 
-#define restricted_branch_speculation_on()				\
+#define ubuntu_restrict_branch_speculation_start()			\
 do {									\
 	u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;			\
 									\
@@ -274,7 +274,7 @@  do {									\
 		native_wrmsrl(MSR_IA32_SPEC_CTRL, val);			\
 } while (0)
 
-#define restricted_branch_speculation_off()				\
+#define ubuntu_restrict_branch_speculation_end()			\
 do {									\
 	u64 val = x86_spec_ctrl_base;					\
 									\
diff --git a/arch/x86/include/asm/spec_ctrl.h b/arch/x86/include/asm/spec_ctrl.h
index e603ee905bab..b4d6ffae202c 100644
--- a/arch/x86/include/asm/spec_ctrl.h
+++ b/arch/x86/include/asm/spec_ctrl.h
@@ -21,11 +21,13 @@ 
 	popq %rdx;				\
 	popq %rcx;				\
 	popq %rax
+
 #define __ASM_ENABLE_IBRS_CLOBBER		\
 	movl $MSR_IA32_SPEC_CTRL, %ecx;		\
 	movl $0, %edx;				\
 	movl $SPEC_CTRL_IBRS, %eax;		\
 	wrmsr;
+
 #define __ASM_DISABLE_IBRS			\
 	pushq %rax;				\
 	pushq %rcx;				\
@@ -37,6 +39,7 @@ 
 	popq %rdx;				\
 	popq %rcx;				\
 	popq %rax
+
 #define __ASM_STUFF_RSB				\
 	call	1f;				\
 	pause;					\
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index f11345902f20..dc9443dea8c8 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -167,14 +167,14 @@  void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
 		if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
 			clflush((void *)&current_thread_info()->flags);
 
-		restricted_branch_speculation_off();
+		ubuntu_restrict_branch_speculation_end();
 
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
 		smp_mb();
 		if (!need_resched())
 			__mwait(ax, cx);
 
-		restricted_branch_speculation_on();
+		ubuntu_restrict_branch_speculation_start();
 	}
 }
 
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index b4a0a26efc0d..c86a805557fc 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -450,16 +450,17 @@  retpoline_auto:
 		setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
 		pr_info("Enabling Restricted Speculation for firmware calls\n");
 
-		/*
-		 * Enable IBRS support if it's not turned off on the
-		 * commandline and we don't have full retpoline mode
-		 */
-		if (!noibrs && mode != SPECTRE_V2_RETPOLINE_AMD &&
-		    mode != SPECTRE_V2_RETPOLINE_GENERIC)
-			ibrs_enable();
-
-		pr_info("%s Indirect Banch Restricted Speculation\n",
-			ibrs_enabled ? "Enabling" : "Disabling");
+		if (noibrs ||
+		    mode == SPECTRE_V2_RETPOLINE_GENERIC ||
+		    mode == SPECTRE_V2_RETPOLINE_AMD) {
+			/*
+			 * IBRS disabled via commandline or the kernel is
+			 * retpoline compiled
+			 */
+			set_ibrs_enabled(0);
+		} else {
+			set_ibrs_enabled(1);
+		}
 	}
 
 	/*
@@ -874,8 +875,9 @@  static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
 		return sprintf(buf, "Mitigation: __user pointer sanitization\n");
 
 	case X86_BUG_SPECTRE_V2:
-		return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
+		return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
 			       ibpb_enabled ? ", IBPB" : "",
+			       ibrs_enabled == 2 ? ", IBRS (user space)" : ibrs_enabled ? ", IBRS" : "",
 			       boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "");
 
 	case X86_BUG_SPEC_STORE_BYPASS:
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index c7e291dbc1e3..d7302c788d15 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -583,15 +583,15 @@  static void mwait_idle(void)
 			mb();
 		}
 
-		restricted_branch_speculation_off();
+		ubuntu_restrict_branch_speculation_end();
 
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
 
 		if (!need_resched()) {
 			__sti_mwait(0, 0);
-			restricted_branch_speculation_on();
+			ubuntu_restrict_branch_speculation_start();
 		} else {
-			restricted_branch_speculation_on();
+			ubuntu_restrict_branch_speculation_start();
 			local_irq_enable();
 		}
 
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 57a339630449..21204d161a6e 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1625,13 +1625,13 @@  void native_play_dead(void)
 	play_dead_common();
 	tboot_shutdown(TB_SHUTDOWN_WFS);
 
-	restricted_branch_speculation_off();
+	ubuntu_restrict_branch_speculation_end();
 
 	mwait_play_dead();	/* Only returns on failure */
 	if (cpuidle_play_dead())
 		hlt_play_dead();
 
-	restricted_branch_speculation_on();
+	ubuntu_restrict_branch_speculation_start();
 }
 
 #else /* ... !CONFIG_HOTPLUG_CPU */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9d3084581410..60e96b6e809d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -249,61 +249,67 @@  static int ibpb_enabled_handler(struct ctl_table *table, int write,
 }
 
 unsigned int ibrs_enabled = 0;
-EXPORT_SYMBOL(ibrs_enabled);
+EXPORT_SYMBOL(ibrs_enabled);   /* Required in some modules */
 
 static unsigned int __ibrs_enabled = 0;   /* procfs shadow variable */
 
-static void set_ibrs_enabled(unsigned int val)
+int set_ibrs_enabled(unsigned int val)
 {
+	int error = 0;
 	unsigned int cpu;
 
 	mutex_lock(&spec_ctrl_mutex);
 
 	/* Only enable/disable IBRS if the CPU supports it */
-	if (boot_cpu_has(X86_FEATURE_USE_IBRS_FW)) {
+	if (boot_cpu_has(X86_FEATURE_IBRS)) {
 		ibrs_enabled = val;
+		pr_info("Spectre V2 : Spectre v2 mitigation: %s Indirect "
+			"Branch Restricted Speculation%s\n",
+			ibrs_enabled ? "Enabling" : "Disabling",
+			ibrs_enabled == 2 ? " (user space)" : "");
+
 		if (ibrs_enabled == 0) {
 			/* Always disable IBRS */
 			u64 val = x86_spec_ctrl_base;
 
-			for_each_online_cpu(cpu)
+			for_each_online_cpu(cpu) {
 				wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, val);
+			}
 		} else if (ibrs_enabled == 2) {
 			/* Always enable IBRS, even in user space */
 			u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;
 
-			for_each_online_cpu(cpu)
+			for_each_online_cpu(cpu) {
 				wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, val);
+			}
 		}
 	} else {
 		ibrs_enabled = 0;
+		if (val) {
+			/* IBRS is not supported but we try to turn it on */
+			error = -EINVAL;
+		}
 	}
 
 	/* Update the shadow variable */
 	__ibrs_enabled = ibrs_enabled;
 
 	mutex_unlock(&spec_ctrl_mutex);
-}
 
-inline void ibrs_enable(void)
-{
-	set_ibrs_enabled(1);
+	return error;
 }
-EXPORT_SYMBOL(ibrs_enable);
 
 static int ibrs_enabled_handler(struct ctl_table *table, int write,
 				void __user *buffer, size_t *lenp,
 				loff_t *ppos)
 {
 	int error;
-	unsigned int cpu;
 
 	error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 	if (error)
 		return error;
 
-	set_ibrs_enabled(__ibrs_enabled);
-	return 0;
+	return set_ibrs_enabled(__ibrs_enabled);
 }
 #endif