⬢ DragonFlyBSD Kernel Audit
DF-3829 / fix.diff
← back to finding ↓ download raw
Proposed fix for DF-3829 (host NMIs swallowed while a vCPU is resident).

DragonFly has no nmi_dispatch() API (NetBSD added one for NVMM), and
`panic_on_nmi` is static to trap.c, so the cleanest self-contained fix in
this file dispatches the NMI's *diagnostics* via isa_nmi() and panics on
hardware-failure NMIs (the default panic_on_nmi=1 semantics).  A fuller
fix would export an nmi_dispatch()-style hook from trap.c and use it
here (and in nvmm_x86_svm.c, which has the same hole).

Note: this diff is authored against the read-only sys/ tree and was
never applied there.  isa_nmi() is declared in
sys/platform/pc64/isa/isa_intr.c and prototyped in machine/md_var.h-
adjacent headers; the include may need adjusting per tree layout.

--- a/sys/dev/virtual/nvmm/x86/nvmm_x86_vmx.c
+++ b/sys/dev/virtual/nvmm/x86/nvmm_x86_vmx.c
@@ -1249,6 +249,20 @@ vmx_exit_invalid(struct nvmm_vcpu_exit *exit, uint64_t code)
 	exit->reason = NVMM_VCPU_EXIT_INVALID;
 }
 
+/*
+ * An NMI that arrived while the vCPU was resident caused the VMexit we
+ * are handling; the host never saw it.  Run the host's NMI diagnostics
+ * (log NMI source; hardware-failure NMIs panic the box, matching
+ * machdep.panic_on_nmi=1 semantics).  DragonFly's equivalent of
+ * NetBSD's nmi_dispatch().
+ */
+static void
+vmx_nmi_dispatch(void)
+{
+	if (isa_nmi(0) != 0)
+		panic("NMI indicates hardware failure");
+	/* no DDB here: no trap frame; host-window NMIs keep that path */
+}
+
 static void
 vmx_exit_exc_nmi(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
     struct nvmm_vcpu_exit *exit)
@@ -1265,6 +1279,9 @@ vmx_exit_exc_nmi(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
 		goto error;
 	}
 
+	/* The NMI was directed at the host: give it to the host. */
+	vmx_nmi_dispatch();
+
 	exit->reason = NVMM_VCPU_EXIT_NONE;
 	return;