]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: nVMX: Fix memory corruption when using VMCS shadowing
authorJim Mattson <jmattson@google.com>
Fri, 8 Jul 2016 22:36:06 +0000 (15:36 -0700)
committerSasha Levin <alexander.levin@verizon.com>
Mon, 22 Aug 2016 16:23:09 +0000 (12:23 -0400)
[ Upstream commit 2f1fe81123f59271bddda673b60116bde9660385 ]

When freeing the nested resources of a vcpu, there is an assumption that
the vcpu's vmcs01 is the current VMCS on the CPU that executes
nested_release_vmcs12(). If this assumption is violated, the vcpu's
vmcs01 may be made active on multiple CPUs at the same time, in
violation of Intel's specification. Moreover, since the vcpu's vmcs01 is
not VMCLEARed on every CPU on which it is active, it can linger in a
CPU's VMCS cache after it has been freed and potentially
repurposed. Subsequent eviction from the CPU's VMCS cache on a capacity
miss can result in memory corruption.

It is not sufficient for vmx_free_vcpu() to call vmx_load_vmcs01(). If
the vcpu in question was last loaded on a different CPU, it must be
migrated to the current CPU before calling vmx_load_vmcs01().

Signed-off-by: Jim Mattson <jmattson@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
arch/x86/kvm/vmx.c
virt/kvm/kvm_main.c

index d9c11f3f5b18928471ad7a3149a30c134c14c747..888eaab57fbc1afe95cc5a108545368874dfc3ff 100644 (file)
@@ -7767,14 +7767,29 @@ static void vmx_load_vmcs01(struct kvm_vcpu *vcpu)
        put_cpu();
 }
 
+/*
+ * Ensure that the current vmcs of the logical processor is the
+ * vmcs01 of the vcpu before calling free_nested().
+ */
+static void vmx_free_vcpu_nested(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int r;
+
+       r = vcpu_load(vcpu);
+       BUG_ON(r);
+       vmx_load_vmcs01(vcpu);
+       free_nested(vmx);
+       vcpu_put(vcpu);
+}
+
 static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
        free_vpid(vmx);
        leave_guest_mode(vcpu);
-       vmx_load_vmcs01(vcpu);
-       free_nested(vmx);
+       vmx_free_vcpu_nested(vcpu);
        free_loaded_vmcs(vmx->loaded_vmcs);
        kfree(vmx->guest_msrs);
        kvm_vcpu_uninit(vcpu);
index 7d32b4e82e86c58d4d36e993cd1b0d48ee1a837f..e013f90f7a29a9d054d59a8d2b71a625b8e3f6c9 100644 (file)
@@ -139,6 +139,7 @@ int vcpu_load(struct kvm_vcpu *vcpu)
        put_cpu();
        return 0;
 }
+EXPORT_SYMBOL_GPL(vcpu_load);
 
 void vcpu_put(struct kvm_vcpu *vcpu)
 {
@@ -148,6 +149,7 @@ void vcpu_put(struct kvm_vcpu *vcpu)
        preempt_enable();
        mutex_unlock(&vcpu->mutex);
 }
+EXPORT_SYMBOL_GPL(vcpu_put);
 
 static void ack_flush(void *_completed)
 {