Blame SOURCES/edk2-OvmfPkg-CpuHotplugSmm-fix-CPU-hotplug-race-just-afte.patch

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