Skip to content

Commit 2f1fe81

Browse files
jsmattsonjrbonzini
authored andcommitted
KVM: nVMX: Fix memory corruption when using VMCS shadowing
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 <[email protected]> Cc: [email protected] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 4e59516 commit 2f1fe81

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

arch/x86/kvm/vmx.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8844,6 +8844,22 @@ static void vmx_load_vmcs01(struct kvm_vcpu *vcpu)
88448844
put_cpu();
88458845
}
88468846

8847+
/*
8848+
* Ensure that the current vmcs of the logical processor is the
8849+
* vmcs01 of the vcpu before calling free_nested().
8850+
*/
8851+
static void vmx_free_vcpu_nested(struct kvm_vcpu *vcpu)
8852+
{
8853+
struct vcpu_vmx *vmx = to_vmx(vcpu);
8854+
int r;
8855+
8856+
r = vcpu_load(vcpu);
8857+
BUG_ON(r);
8858+
vmx_load_vmcs01(vcpu);
8859+
free_nested(vmx);
8860+
vcpu_put(vcpu);
8861+
}
8862+
88478863
static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
88488864
{
88498865
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -8852,8 +8868,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
88528868
vmx_destroy_pml_buffer(vmx);
88538869
free_vpid(vmx->vpid);
88548870
leave_guest_mode(vcpu);
8855-
vmx_load_vmcs01(vcpu);
8856-
free_nested(vmx);
8871+
vmx_free_vcpu_nested(vcpu);
88578872
free_loaded_vmcs(vmx->loaded_vmcs);
88588873
kfree(vmx->guest_msrs);
88598874
kvm_vcpu_uninit(vcpu);

virt/kvm/kvm_main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ int vcpu_load(struct kvm_vcpu *vcpu)
148148
put_cpu();
149149
return 0;
150150
}
151+
EXPORT_SYMBOL_GPL(vcpu_load);
151152

152153
void vcpu_put(struct kvm_vcpu *vcpu)
153154
{
@@ -157,6 +158,7 @@ void vcpu_put(struct kvm_vcpu *vcpu)
157158
preempt_enable();
158159
mutex_unlock(&vcpu->mutex);
159160
}
161+
EXPORT_SYMBOL_GPL(vcpu_put);
160162

161163
static void ack_flush(void *_completed)
162164
{

0 commit comments

Comments
 (0)