]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: nVMX: Hide shadow VMCS right after VMCLEAR
authorHyunwoo Kim <imv4bel@gmail.com>
Fri, 17 Jul 2026 10:30:11 +0000 (12:30 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 21 Jul 2026 10:24:49 +0000 (12:24 +0200)
free_nested() frees the shadow VMCS while vmcs01 still points to it. But
because it is asynchronous with respect to loaded_vmcs_clear(), the vCPU
might migrate before the pointer is cleared and __loaded_vmcs_clear()
may then execute VMCLEAR.

The VMCS needs to stay attached until its explicit VMCLEAR completes, but
then it can be hidden and the page safely freed.

Fixes: 355f4fb1405e ("kvm: nVMX: VMCLEAR an active shadow VMCS after last use")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/nested.c

index 220d42ebc82e50a90dead11b9d1eca55aa703289..ddf6df7bee93b224f505a38644b4b4f6759dd9b2 100644 (file)
@@ -336,6 +336,7 @@ static void nested_put_vmcs12_pages(struct kvm_vcpu *vcpu)
 static void free_nested(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct vmcs *shadow_vmcs;
 
        if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01))
                vmx_switch_vmcs(vcpu, &vmx->vmcs01);
@@ -353,9 +354,15 @@ static void free_nested(struct kvm_vcpu *vcpu)
        vmx->nested.current_vmptr = INVALID_GPA;
        if (enable_shadow_vmcs) {
                vmx_disable_shadow_vmcs(vmx);
-               vmcs_clear(vmx->vmcs01.shadow_vmcs);
-               free_vmcs(vmx->vmcs01.shadow_vmcs);
+
+               /*
+                * Keep the pointer visible until after VMCLEAR, so migration
+                * can clear an active shadow VMCS on the old CPU.
+                */
+               shadow_vmcs = vmx->vmcs01.shadow_vmcs;
+               vmcs_clear(shadow_vmcs);
                vmx->vmcs01.shadow_vmcs = NULL;
+               free_vmcs(shadow_vmcs);
        }
        kfree(vmx->nested.cached_vmcs12);
        vmx->nested.cached_vmcs12 = NULL;