55 lines
2.0 KiB
Diff
55 lines
2.0 KiB
Diff
From 665c3ad7f18b63fba85a93250a75d44a5454734d Mon Sep 17 00:00:00 2001
|
|
From: Aidan Wallace <awallace@redhat.com>
|
|
Date: Wed, 22 Jul 2026 00:43:20 -0500
|
|
Subject: [PATCH] KVM: nVMX: Hide shadow VMCS right after VMCLEAR
|
|
|
|
JIRA: https://redhat.atlassian.net/browse/RHEL-213327
|
|
|
|
KVM: nVMX: Hide shadow VMCS right after VMCLEAR
|
|
|
|
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>
|
|
(cherry picked from commit 622ebfac01ba4f9c0060cebd41257fe46fc4a0b3)
|
|
Signed-off-by: Aidan Wallace <awallace@redhat.com>
|
|
|
|
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
|
|
index 5570e0c..49d7cda 100644
|
|
--- a/arch/x86/kvm/vmx/nested.c
|
|
+++ b/arch/x86/kvm/vmx/nested.c
|
|
@@ -331,6 +331,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);
|
|
@@ -348,9 +349,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;
|