|
|
f60719 |
From 08a95c3541cbe2b3a1c671fa683bd6214ad996f0 Mon Sep 17 00:00:00 2001
|
|
|
f60719 |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
f60719 |
Date: Thu, 27 Aug 2020 00:21:29 +0200
|
|
|
f60719 |
Subject: [PATCH 3/5] OvmfPkg/CpuHotplugSmm: fix CPU hotplug race just after
|
|
|
f60719 |
SMI broadcast
|
|
|
f60719 |
MIME-Version: 1.0
|
|
|
f60719 |
Content-Type: text/plain; charset=UTF-8
|
|
|
f60719 |
Content-Transfer-Encoding: 8bit
|
|
|
f60719 |
|
|
|
f60719 |
RH-Author: Laszlo Ersek (lersek)
|
|
|
f60719 |
RH-MergeRequest: 1: [RHEL-8.4.0] complete the "VCPU hotplug with SMI" OVMF feature
|
|
|
f60719 |
RH-Commit: [3/3] 40521ea89725b8b0ff8ca3f0a610ff45431e610e (lersek/edk2)
|
|
|
f60719 |
RH-Bugzilla: 1849177
|
|
|
f60719 |
|
|
|
f60719 |
The "virsh setvcpus" (plural) command may hot-plug several VCPUs in quick
|
|
|
f60719 |
succession -- it means a series of "device_add" QEMU monitor commands,
|
|
|
f60719 |
back-to-back.
|
|
|
f60719 |
|
|
|
f60719 |
If a "device_add" occurs *just after* ACPI raises the broadcast SMI, then:
|
|
|
f60719 |
|
|
|
f60719 |
- the CPU_FOREACH() loop in QEMU's ich9_apm_ctrl_changed() cannot make the
|
|
|
f60719 |
SMI pending for the new CPU -- at that time, the new CPU doesn't even
|
|
|
f60719 |
exist yet,
|
|
|
f60719 |
|
|
|
f60719 |
- OVMF will find the new CPU however (in the CPU hotplug register block),
|
|
|
f60719 |
in QemuCpuhpCollectApicIds().
|
|
|
f60719 |
|
|
|
f60719 |
As a result, when the firmware sends an INIT-SIPI-SIPI to the new CPU in
|
|
|
f60719 |
SmbaseRelocate(), expecting it to boot into SMM (due to the pending SMI),
|
|
|
f60719 |
the new CPU instead boots straight into the post-RSM (normal mode) "pen",
|
|
|
f60719 |
skipping its initial SMI handler.
|
|
|
f60719 |
|
|
|
f60719 |
The CPU halts nicely in the pen, but its SMBASE is never relocated, and
|
|
|
f60719 |
the SMRAM message exchange with the BSP falls apart -- the BSP gets stuck
|
|
|
f60719 |
in the following loop:
|
|
|
f60719 |
|
|
|
f60719 |
//
|
|
|
f60719 |
// Wait until the hot-added CPU is just about to execute RSM.
|
|
|
f60719 |
//
|
|
|
f60719 |
while (Context->AboutToLeaveSmm == 0) {
|
|
|
f60719 |
CpuPause ();
|
|
|
f60719 |
}
|
|
|
f60719 |
|
|
|
f60719 |
because the new CPU's initial SMI handler never sets the flag to nonzero.
|
|
|
f60719 |
|
|
|
f60719 |
Fix this by sending a directed SMI to the new CPU just before sending it
|
|
|
f60719 |
the INIT-SIPI-SIPI. The various scenarios are documented in the code --
|
|
|
f60719 |
the cases affected by the patch are documented under point (2).
|
|
|
f60719 |
|
|
|
f60719 |
Note that this is not considered a security patch, as for a malicious
|
|
|
f60719 |
guest OS, the issue is not exploitable -- the symptom is a hang on the
|
|
|
f60719 |
BSP, in the above-noted loop in SmbaseRelocate(). Instead, the patch fixes
|
|
|
f60719 |
behavior for a benign guest OS.
|
|
|
f60719 |
|
|
|
f60719 |
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
|
|
|
f60719 |
Cc: Igor Mammedov <imammedo@redhat.com>
|
|
|
f60719 |
Cc: Jordan Justen <jordan.l.justen@intel.com>
|
|
|
f60719 |
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
|
|
|
f60719 |
Fixes: 51a6fb41181529e4b50ea13377425bda6bb69ba6
|
|
|
f60719 |
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2929
|
|
|
f60719 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
f60719 |
Message-Id: <20200826222129.25798-3-lersek@redhat.com>
|
|
|
f60719 |
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
|
|
|
f60719 |
(cherry picked from commit cbccf995920a28071f5403b847f29ebf8b732fa9)
|
|
|
f60719 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
f60719 |
---
|
|
|
f60719 |
OvmfPkg/CpuHotplugSmm/Smbase.c | 35 ++++++++++++++++++++++++++++------
|
|
|
f60719 |
1 file changed, 29 insertions(+), 6 deletions(-)
|
|
|
f60719 |
|
|
|
f60719 |
diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.c b/OvmfPkg/CpuHotplugSmm/Smbase.c
|
|
|
f60719 |
index 170571221d..d8f45c4313 100644
|
|
|
f60719 |
--- a/OvmfPkg/CpuHotplugSmm/Smbase.c
|
|
|
f60719 |
+++ b/OvmfPkg/CpuHotplugSmm/Smbase.c
|
|
|
f60719 |
@@ -220,14 +220,37 @@ SmbaseRelocate (
|
|
|
f60719 |
//
|
|
|
f60719 |
// Boot the hot-added CPU.
|
|
|
f60719 |
//
|
|
|
f60719 |
- // If the OS is benign, and so the hot-added CPU is still in RESET state,
|
|
|
f60719 |
- // then the broadcast SMI is still pending for it; it will now launch
|
|
|
f60719 |
- // directly into SMM.
|
|
|
f60719 |
+ // There are 2*2 cases to consider:
|
|
|
f60719 |
//
|
|
|
f60719 |
- // If the OS is malicious, the hot-added CPU has been booted already, and so
|
|
|
f60719 |
- // it is already spinning on the APIC ID gate. In that case, the
|
|
|
f60719 |
- // INIT-SIPI-SIPI below will be ignored.
|
|
|
f60719 |
+ // (1) The CPU was hot-added before the SMI was broadcast.
|
|
|
f60719 |
//
|
|
|
f60719 |
+ // (1.1) The OS is benign.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // The hot-added CPU is in RESET state, with the broadcast SMI pending
|
|
|
f60719 |
+ // for it. The directed SMI below will be ignored (it's idempotent),
|
|
|
f60719 |
+ // and the INIT-SIPI-SIPI will launch the CPU directly into SMM.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // (1.2) The OS is malicious.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // The hot-added CPU has been booted, by the OS. Thus, the hot-added
|
|
|
f60719 |
+ // CPU is spinning on the APIC ID gate. In that case, both the SMI and
|
|
|
f60719 |
+ // the INIT-SIPI-SIPI below will be ignored.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // (2) The CPU was hot-added after the SMI was broadcast.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // (2.1) The OS is benign.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // The hot-added CPU is in RESET state, with no SMI pending for it. The
|
|
|
f60719 |
+ // directed SMI will latch the SMI for the CPU. Then the INIT-SIPI-SIPI
|
|
|
f60719 |
+ // will launch the CPU into SMM.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // (2.2) The OS is malicious.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ // The hot-added CPU is executing OS code. The directed SMI will pull
|
|
|
f60719 |
+ // the hot-added CPU into SMM, where it will start spinning on the APIC
|
|
|
f60719 |
+ // ID gate. The INIT-SIPI-SIPI will be ignored.
|
|
|
f60719 |
+ //
|
|
|
f60719 |
+ SendSmiIpi (ApicId);
|
|
|
f60719 |
SendInitSipiSipi (ApicId, PenAddress);
|
|
|
f60719 |
|
|
|
f60719 |
//
|
|
|
f60719 |
--
|
|
|
f60719 |
2.27.0
|
|
|
f60719 |
|