[Devel] [PATCH vz9 5/9] ms/KVM: VMX: Reset eVMCS controls in VP assist page during hardware disabling

Konstantin Khorenko khorenko at virtuozzo.com
Wed Nov 1 16:38:52 MSK 2023


From: Maxim Levitsky <mlevitsk at redhat.com>

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2177720

commit 2916b70fc342719f570640de07251b7f91feebdb
Author: Sean Christopherson <seanjc at google.com>
Date:   Wed Nov 30 23:08:54 2022 +0000

    KVM: VMX: Reset eVMCS controls in VP assist page during hardware disabling

    Reset the eVMCS controls in the per-CPU VP assist page during hardware
    disabling instead of waiting until kvm-intel's module exit.  The controls
    are activated if and only if KVM creates a VM, i.e. don't need to be
    reset if hardware is never enabled.

    Doing the reset during hardware disabling will naturally fix a potential
    NULL pointer deref bug once KVM disables CPU hotplug while enabling and
    disabling hardware (which is necessary to fix a variety of bugs).  If the
    kernel is running as the root partition, the VP assist page is unmapped
    during CPU hot unplug, and so KVM's clearing of the eVMCS controls needs
    to occur with CPU hot(un)plug disabled, otherwise KVM could attempt to
    write to a CPU's VP assist page after it's unmapped.

    Reported-by: Vitaly Kuznetsov <vkuznets at redhat.com>
    Signed-off-by: Sean Christopherson <seanjc at google.com>
    Reviewed-by: Vitaly Kuznetsov <vkuznets at redhat.com>
    Message-Id: <20221130230934.1014142-11-seanjc at google.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

Signed-off-by: Maxim Levitsky <mlevitsk at redhat.com>

(cherry picked from CentOS 9 Stream commit 9828ea8dc4fb)
https://pmc.acronis.work/browse/VSTOR-76102
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

Feature: fix ms/KVM
---
 arch/x86/kvm/vmx/vmx.c | 50 +++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 2f792d84226c..e0c507fcd09e 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -552,6 +552,33 @@ static int hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static void hv_reset_evmcs(void)
+{
+	struct hv_vp_assist_page *vp_ap;
+
+	if (!static_branch_unlikely(&enable_evmcs))
+		return;
+
+	/*
+	 * KVM should enable eVMCS if and only if all CPUs have a VP assist
+	 * page, and should reject CPU onlining if eVMCS is enabled the CPU
+	 * doesn't have a VP assist page allocated.
+	 */
+	vp_ap = hv_get_vp_assist_page(smp_processor_id());
+	if (WARN_ON_ONCE(!vp_ap))
+		return;
+
+	/*
+	 * Reset everything to support using non-enlightened VMCS access later
+	 * (e.g. when we reload the module with enlightened_vmcs=0)
+	 */
+	vp_ap->nested_control.features.directhypercall = 0;
+	vp_ap->current_nested_vmcs = 0;
+	vp_ap->enlighten_vmentry = 0;
+}
+
+#else /* IS_ENABLED(CONFIG_HYPERV) */
+static void hv_reset_evmcs(void) {}
 #endif /* IS_ENABLED(CONFIG_HYPERV) */
 
 /*
@@ -2483,6 +2510,8 @@ static void vmx_hardware_disable(void)
 	if (cpu_vmxoff())
 		kvm_spurious_fault();
 
+	hv_reset_evmcs();
+
 	intel_pt_handle_vmx(0);
 }
 
@@ -8410,27 +8439,8 @@ static void vmx_exit(void)
 	kvm_exit();
 
 #if IS_ENABLED(CONFIG_HYPERV)
-	if (static_branch_unlikely(&enable_evmcs)) {
-		int cpu;
-		struct hv_vp_assist_page *vp_ap;
-		/*
-		 * Reset everything to support using non-enlightened VMCS
-		 * access later (e.g. when we reload the module with
-		 * enlightened_vmcs=0)
-		 */
-		for_each_online_cpu(cpu) {
-			vp_ap =	hv_get_vp_assist_page(cpu);
-
-			if (!vp_ap)
-				continue;
-
-			vp_ap->nested_control.features.directhypercall = 0;
-			vp_ap->current_nested_vmcs = 0;
-			vp_ap->enlighten_vmentry = 0;
-		}
-
+	if (static_branch_unlikely(&enable_evmcs))
 		static_branch_disable(&enable_evmcs);
-	}
 #endif
 	vmx_cleanup_l1d_flush();
 
-- 
2.39.3



More information about the Devel mailing list