Xen Security Advisory 431 v1 (CVE-2022-42336) - Mishandling of guest SSBD selection on AMD hardware

Xen.org security team posted 1 patch 11 months, 3 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/E1pywNt-00034k-MT@xenbits.xenproject.org
xen/arch/x86/cpu/amd.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
Xen Security Advisory 431 v1 (CVE-2022-42336) - Mishandling of guest SSBD selection on AMD hardware
Posted by Xen.org security team 11 months, 3 weeks ago
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

            Xen Security Advisory CVE-2022-42336 / XSA-431

          Mishandling of guest SSBD selection on AMD hardware

ISSUE DESCRIPTION
=================

The current logic to set SSBD on AMD Family 17h and Hygon Family 18h
processors requires that the setting of SSBD is coordinated at a core
level, as the setting is shared between threads.  Logic was introduced
to keep track of how many threads require SSBD active in order to
coordinate it, such logic relies on using a per-core counter of threads
that have SSBD active.

When running on the mentioned hardware, it's possible for a guest to
under or overflow the thread counter, because each write to
VIRT_SPEC_CTRL.SSBD by the guest gets propagated to the helper that does
the per-core active accounting.  Underflowing the counter causes the
value to get saturated, and thus attempts for guests running on the same
core to set SSBD won't have effect because the hypervisor assumes it's
already active.

IMPACT
======

An attacker with control over a guest can mislead other guests into
observing SSBD active when it is not.

VULNERABLE SYSTEMS
==================

Only Xen version 4.17 is vulnerable.

Only x86 AMD systems are vulnerable.  The vulnerability can be leveraged
by and affects only HVM guests.

MITIGATION
==========

Running PV guests only will prevent the vulnerability.

Setting `spec-ctrl=ssbd` on the hypervisor command line will force SSBD
to be unconditionally active.

NOTE REGARDING LACK OF EMBARGO
==============================

This issue was discussed in public already.

RESOLUTION
==========

Applying the attached patch resolves this issue.

Note that patches for released versions are generally prepared to
apply to the stable branches, and may not apply cleanly to the most
recent release tarball.  Downstreams are encouraged to update to the
tip of the stable branch before applying these patches.

xsa431.patch           xen-unstable - Xen 4.17.x

$ sha256sum xsa431*
e71a8b7e251adf4832a4de9e452c2fd895a56314729c54698d10e344f1996a99  xsa431.patch
$
-----BEGIN PGP SIGNATURE-----

iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAmRjkhsMHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZDb8H/0vKLOgBhwKCVc8VYm59FIALd69k4qCLcwwfDuro
jFum5ATC3Cbx+iEXD2URFY6O+eE71mMBqw3/GT/BiKvsBHQhX5lsJUpxZFscqW9J
diM69a9BYuNNy+qW3TsslRsW9WGHH5bZoAhxpNKgciE17svJ76IRUsgNf806VRX+
VBI61wK2s9oqzfTazhQVR9zxFLANTyw7M4EtUXs0y49IUFjnSeVpW7/PdoloPC1C
m0SG6HSIJ4bH+yAWMqY5GYYVgJOkaStxEM6YLGjT/V078xcDyW2cie3BOtQ8/BI0
FJ7iwEh932k7VLtd+htBF3vo7CD+teGneeaktqKK2h55ps0=
=dmhW
-----END PGP SIGNATURE-----
From 9c03380fc9e328f0ccba860cbe09ef58ea366f71 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Wed, 22 Mar 2023 11:52:07 +0100
Subject: [PATCH] x86/amd: fix legacy setting of SSBD on AMD Family 17h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The current logic to set SSBD on AMD Family 17h and Hygon Family 18h
processors requires that the setting of SSBD is coordinated at a core
level, as the setting is shared between threads.  Logic was introduced
to keep track of how many threads require SSBD active in order to
coordinate it, such logic relies on using a per-core counter of
threads that have SSBD active.

Given the current logic, it's possible for a guest to under or
overflow the thread counter, because each write to VIRT_SPEC_CTRL.SSBD
by the guest gets propagated to the helper that does the per-core
active accounting.  Overflowing the counter is not so much of an
issue, as this would just make SSBD sticky.

Underflowing however is more problematic: on non-debug Xen builds a
guest can perform empty writes to VIRT_SPEC_CTRL that would cause the
counter to underflow and thus the value gets saturated to the max
value of unsigned int.  At which points attempts from any thread to
set VIRT_SPEC_CTRL.SSBD won't get propagated to the hardware anymore,
because the logic will see that the counter is greater than 1 and
assume that SSBD is already active, effectively loosing the setting
of SSBD and the protection it provides.

Fix this by introducing a per-CPU variable that keeps track of whether
the current thread has legacy SSBD active or not, and thus only
attempt to propagate the value to the hardware once the thread
selected value changes.

This is XSA-431 / CVE-2022-42336

Fixes: b2030e6730a2 ('amd/virt_ssbd: set SSBD at vCPU context switch')
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/cpu/amd.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index caafe4474021..9a1a3858edd4 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -783,12 +783,23 @@ bool __init amd_setup_legacy_ssbd(void)
 	return true;
 }
 
+/*
+ * legacy_ssbd is always initialized to false because when SSBD is set
+ * from the command line guest attempts to change it are a no-op (see
+ * amd_set_legacy_ssbd()), whereas when SSBD is inactive hardware will
+ * be forced into that mode (see amd_init_ssbd()).
+ */
+static DEFINE_PER_CPU(bool, legacy_ssbd);
+
+/* Must be called only when the SSBD setting needs toggling. */
 static void core_set_legacy_ssbd(bool enable)
 {
 	const struct cpuinfo_x86 *c = &current_cpu_data;
 	struct ssbd_ls_cfg *status;
 	unsigned long flags;
 
+	BUG_ON(this_cpu(legacy_ssbd) == enable);
+
 	if ((c->x86 != 0x17 && c->x86 != 0x18) || c->x86_num_siblings <= 1) {
 		BUG_ON(!set_legacy_ssbd(c, enable));
 		return;
@@ -816,12 +827,17 @@ void amd_set_legacy_ssbd(bool enable)
 		 */
 		return;
 
+	if (this_cpu(legacy_ssbd) == enable)
+		return;
+
 	if (cpu_has_virt_ssbd)
 		wrmsr(MSR_VIRT_SPEC_CTRL, enable ? SPEC_CTRL_SSBD : 0, 0);
 	else if (amd_legacy_ssbd)
 		core_set_legacy_ssbd(enable);
 	else
 		ASSERT_UNREACHABLE();
+
+	this_cpu(legacy_ssbd) = enable;
 }
 
 /*
-- 
2.40.0