From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tim Chen <tim.c.chen@linux.intel.com>
Date: Mon, 6 Nov 2017 18:19:14 -0800
Subject: [PATCH] x86/idle: Disable IBRS entering idle and enable it on wakeup
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

CVE-2017-5753
CVE-2017-5715

Clear IBRS on idle entry and set it on idle exit into kernel on mwait.

Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Andy Whitcroft <apw@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
(cherry picked from commit 5521b04afda1d683c1ebad6c25c2529a88e6f061)
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 arch/x86/include/asm/mwait.h |  8 ++++++++
 arch/x86/kernel/process.c    | 12 ++++++++++--
 arch/x86/lib/delay.c         | 10 ++++++++++
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h
index bda3c27f0da0..f15120ada161 100644
--- a/arch/x86/include/asm/mwait.h
+++ b/arch/x86/include/asm/mwait.h
@@ -5,6 +5,8 @@
 #include <linux/sched/idle.h>
 
 #include <asm/cpufeature.h>
+#include <asm/spec_ctrl.h>
+#include <asm/microcode.h>
 
 #define MWAIT_SUBSTATE_MASK		0xf
 #define MWAIT_CSTATE_MASK		0xf
@@ -105,9 +107,15 @@ static inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 			mb();
 		}
 
+		if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+			native_wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
 		if (!need_resched())
 			__mwait(eax, ecx);
+
+		if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+			native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
 	}
 	current_clr_polling();
 }
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 07e6218ad7d9..3adb3806a284 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -447,11 +447,19 @@ static __cpuidle void mwait_idle(void)
 			mb(); /* quirk */
 		}
 
+		if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+                        native_wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
-		if (!need_resched())
+		if (!need_resched()) {
 			__sti_mwait(0, 0);
-		else
+			if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+				native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
+		} else {
+			if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+				native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
 			local_irq_enable();
+		}
 		trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 	} else {
 		local_irq_enable();
diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c
index cf2ac227c2ac..b088463973e4 100644
--- a/arch/x86/lib/delay.c
+++ b/arch/x86/lib/delay.c
@@ -26,6 +26,8 @@
 # include <asm/smp.h>
 #endif
 
+#define IBRS_DISABLE_THRESHOLD	1000
+
 /* simple loop based delay: */
 static void delay_loop(unsigned long loops)
 {
@@ -105,6 +107,10 @@ static void delay_mwaitx(unsigned long __loops)
 	for (;;) {
 		delay = min_t(u64, MWAITX_MAX_LOOPS, loops);
 
+		if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) &&
+			(delay > IBRS_DISABLE_THRESHOLD))
+			native_wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
 		/*
 		 * Use cpu_tss_rw as a cacheline-aligned, seldomly
 		 * accessed per-cpu variable as the monitor target.
@@ -118,6 +124,10 @@ static void delay_mwaitx(unsigned long __loops)
 		 */
 		__mwaitx(MWAITX_DISABLE_CSTATES, delay, MWAITX_ECX_TIMER_ENABLE);
 
+		if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) &&
+			(delay > IBRS_DISABLE_THRESHOLD))
+			native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
+
 		end = rdtsc_ordered();
 
 		if (loops <= end - start)
-- 
2.14.2

