⬢ DragonFlyBSD Kernel Audit
DF-3978 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/virtual/nvmm/x86/nvmm_x86_svm.c b/sys/dev/virtual/nvmm/x86/nvmm_x86_svm.c
index 83afb64..4cc143b 100644
--- a/sys/dev/virtual/nvmm/x86/nvmm_x86_svm.c
+++ b/sys/dev/virtual/nvmm/x86/nvmm_x86_svm.c
@@ -583,6 +583,9 @@ struct svm_cpudata {
 	struct {
 		uint64_t fsbase;
 		uint64_t kernelgsbase;
+		uint64_t sysenter_cs;
+		uint64_t sysenter_esp;
+		uint64_t sysenter_eip;
 		uint64_t drs[NVMM_X64_NDR];
 #ifdef __DragonFly__
 		mcontext_t hmctx;  /* TODO: remove this like NetBSD */
@@ -1518,6 +1521,9 @@ svm_vcpu_guest_misc_enter(struct nvmm_cpu *vcpu)
 	/* Save the percpu host state. */
 	cpudata->hstate.fsbase = rdmsr(MSR_FSBASE);
 	cpudata->hstate.kernelgsbase = rdmsr(MSR_KERNELGSBASE);
+	cpudata->hstate.sysenter_cs = rdmsr(MSR_SYSENTER_CS);
+	cpudata->hstate.sysenter_esp = rdmsr(MSR_SYSENTER_ESP);
+	cpudata->hstate.sysenter_eip = rdmsr(MSR_SYSENTER_EIP);
 }
 
 static void
@@ -1534,6 +1540,17 @@ svm_vcpu_guest_misc_leave(struct nvmm_cpu *vcpu)
 	/* Restore the percpu host state. */
 	wrmsr(MSR_FSBASE, cpudata->hstate.fsbase);
 	wrmsr(MSR_KERNELGSBASE, cpudata->hstate.kernelgsbase);
+
+	/*
+	 * Restore the host SYSENTER MSRs.  VMLOAD loads the guest values
+	 * into the hardware MSRs and #VMEXIT does not restore the host
+	 * values (the host save area does not cover them), so without this
+	 * restore the guest controls IA32_SYSENTER_EIP/ESP/CS for the whole
+	 * host and any process can pivot to ring 0 via `sysenter`.
+	 */
+	wrmsr(MSR_SYSENTER_CS, cpudata->hstate.sysenter_cs);
+	wrmsr(MSR_SYSENTER_ESP, cpudata->hstate.sysenter_esp);
+	wrmsr(MSR_SYSENTER_EIP, cpudata->hstate.sysenter_eip);
 }
 
 /* -------------------------------------------------------------------------- */