KVM: nVMX: Always flush vpid02 on first use

Make sure vpid02 is always flushed on first use by setting last_vpid=0
when allocating vpid02.  nested_vmx_transition_tlb_flush() will always
detect a VPID change on first VM-Enter after VMXON, because VPID=0 in
vmcs12 is not allowed if L1 enables VPID.

This avoids using stale TLB entries from a previous lifetime of the
VPID, that might have been associated with a different vCPU (or a
completely different VM).

Note that last_vpid is already being initialized as 0 when the vCPU is
created, but it is not reset when vpid02 is freed on VMXOFF. Hence, the
problem can only occur if L1 does VMXOFF -> VMXON, runs an L2, and KVM
happens to reuse a VPID that has TLB entries on the physical CPU.

Cc: stable@vger.kernel.org
Signed-off-by: Yosry Ahmed <yosry@kernel.org>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Jim Mattson <jmattson@google.com>
Link: https://patch.msgid.link/20260616214652.2157032-2-yosry@kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Yosry Ahmed 2026-06-16 21:46:50 +00:00 committed by Sean Christopherson
parent a204badd84
commit f077238941

View File

@ -1289,6 +1289,9 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
* is the VPID incorporated into the MMU context. I.e. KVM must assume
* that the new vpid12 has never been used and thus represents a new
* guest ASID that cannot have entries in the TLB.
*
* Note, last_vpid is initialized as 0, so the first nested VM-Enter
* after VMXON will always flush the TLB to avoid using stale entries.
*/
if (is_vmenter && vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
vmx->nested.last_vpid = vmcs12->virtual_processor_id;
@ -5435,6 +5438,13 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu)
vmx->nested.vpid02 = allocate_vpid();
/*
* Clear last_vpid to ensure that the VPID is flushed on the first
* nested VM-Enter. Otherwise, stale TLB entries from a previous life of
* the VPID (e.g. different vCPU or even different VM) could be used.
*/
vmx->nested.last_vpid = 0;
vmx->nested.vmcs02_initialized = false;
vmx->nested.vmxon = true;