f3cac52
From 9c03380fc9e328f0ccba860cbe09ef58ea366f71 Mon Sep 17 00:00:00 2001
f3cac52
From: Roger Pau Monne <roger.pau@citrix.com>
f3cac52
Date: Wed, 22 Mar 2023 11:52:07 +0100
f3cac52
Subject: [PATCH] x86/amd: fix legacy setting of SSBD on AMD Family 17h
f3cac52
MIME-Version: 1.0
f3cac52
Content-Type: text/plain; charset=UTF-8
f3cac52
Content-Transfer-Encoding: 8bit
f3cac52
f3cac52
The current logic to set SSBD on AMD Family 17h and Hygon Family 18h
f3cac52
processors requires that the setting of SSBD is coordinated at a core
f3cac52
level, as the setting is shared between threads.  Logic was introduced
f3cac52
to keep track of how many threads require SSBD active in order to
f3cac52
coordinate it, such logic relies on using a per-core counter of
f3cac52
threads that have SSBD active.
f3cac52
f3cac52
Given the current logic, it's possible for a guest to under or
f3cac52
overflow the thread counter, because each write to VIRT_SPEC_CTRL.SSBD
f3cac52
by the guest gets propagated to the helper that does the per-core
f3cac52
active accounting.  Overflowing the counter is not so much of an
f3cac52
issue, as this would just make SSBD sticky.
f3cac52
f3cac52
Underflowing however is more problematic: on non-debug Xen builds a
f3cac52
guest can perform empty writes to VIRT_SPEC_CTRL that would cause the
f3cac52
counter to underflow and thus the value gets saturated to the max
f3cac52
value of unsigned int.  At which points attempts from any thread to
f3cac52
set VIRT_SPEC_CTRL.SSBD won't get propagated to the hardware anymore,
f3cac52
because the logic will see that the counter is greater than 1 and
f3cac52
assume that SSBD is already active, effectively loosing the setting
f3cac52
of SSBD and the protection it provides.
f3cac52
f3cac52
Fix this by introducing a per-CPU variable that keeps track of whether
f3cac52
the current thread has legacy SSBD active or not, and thus only
f3cac52
attempt to propagate the value to the hardware once the thread
f3cac52
selected value changes.
f3cac52
f3cac52
This is XSA-431 / CVE-2022-42336
f3cac52
f3cac52
Fixes: b2030e6730a2 ('amd/virt_ssbd: set SSBD at vCPU context switch')
f3cac52
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
f3cac52
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
f3cac52
Reviewed-by: Jan Beulich <jbeulich@suse.com>
f3cac52
---
f3cac52
 xen/arch/x86/cpu/amd.c | 16 ++++++++++++++++
f3cac52
 1 file changed, 16 insertions(+)
f3cac52
f3cac52
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
f3cac52
index caafe4474021..9a1a3858edd4 100644
f3cac52
--- a/xen/arch/x86/cpu/amd.c
f3cac52
+++ b/xen/arch/x86/cpu/amd.c
f3cac52
@@ -783,12 +783,23 @@ bool __init amd_setup_legacy_ssbd(void)
f3cac52
 	return true;
f3cac52
 }
f3cac52
 
f3cac52
+/*
f3cac52
+ * legacy_ssbd is always initialized to false because when SSBD is set
f3cac52
+ * from the command line guest attempts to change it are a no-op (see
f3cac52
+ * amd_set_legacy_ssbd()), whereas when SSBD is inactive hardware will
f3cac52
+ * be forced into that mode (see amd_init_ssbd()).
f3cac52
+ */
f3cac52
+static DEFINE_PER_CPU(bool, legacy_ssbd);
f3cac52
+
f3cac52
+/* Must be called only when the SSBD setting needs toggling. */
f3cac52
 static void core_set_legacy_ssbd(bool enable)
f3cac52
 {
f3cac52
 	const struct cpuinfo_x86 *c = &current_cpu_data;
f3cac52
 	struct ssbd_ls_cfg *status;
f3cac52
 	unsigned long flags;
f3cac52
 
f3cac52
+	BUG_ON(this_cpu(legacy_ssbd) == enable);
f3cac52
+
f3cac52
 	if ((c->x86 != 0x17 && c->x86 != 0x18) || c->x86_num_siblings <= 1) {
f3cac52
 		BUG_ON(!set_legacy_ssbd(c, enable));
f3cac52
 		return;
f3cac52
@@ -816,12 +827,17 @@ void amd_set_legacy_ssbd(bool enable)
f3cac52
 		 */
f3cac52
 		return;
f3cac52
 
f3cac52
+	if (this_cpu(legacy_ssbd) == enable)
f3cac52
+		return;
f3cac52
+
f3cac52
 	if (cpu_has_virt_ssbd)
f3cac52
 		wrmsr(MSR_VIRT_SPEC_CTRL, enable ? SPEC_CTRL_SSBD : 0, 0);
f3cac52
 	else if (amd_legacy_ssbd)
f3cac52
 		core_set_legacy_ssbd(enable);
f3cac52
 	else
f3cac52
 		ASSERT_UNREACHABLE();
f3cac52
+
f3cac52
+	this_cpu(legacy_ssbd) = enable;
f3cac52
 }
f3cac52
 
f3cac52
 /*
f3cac52
-- 
f3cac52
2.40.0
f3cac52