|
|
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 = ¤t_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 |
|