Re: [Bug 221841] KVM: nested VMX eVMCS VMPTRLD/VMPTRST causes infinite VM-Exit loop due to missing RIP advance
Sean Christopherson <[email protected]>
| Newsgroups | org.kernel.vger.kvm |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Aug 07, 2026, [email protected] wrote: > > > The eVMCS path should behave similarly to other unsupported nested VMX > > > instructions. > > > > Only if the TLFS allows it. I assume it just says "unsupported" or > > "undefined behavior", i.e. KVM can probably do whatever it wants. Vitaly? > > VMREAD/VMWRITE with eVMCS are explicitly called 'unsupported' in the TLFS: > > "Any VMREAD or VMWRITE instructions while an enlightened VMCS is active is > unsupported and can result in unexpected behavior.". > > As for VMPTRLD, we only have > "No VMPTRLD instruction must be executed to make an enlightened VMCS active or > current." but there's nothing about the expected result there. VMPTRST is not > mentioned. > > So I guess we can do whatever we want in KVM and skipping the instruction is > not a bad thing. Ideally, we can try and see what genuine Hyper-V gives us in > this situation (by e.g. running an instrumented version of KVM there). Heh, I agree, so long as Hyper-V's behavior is to either signal VM-Fail or inject an exception of some kind. If Hyper-V loops (like KVM does) or skips the instruction without synthesizing an error of some kind, then I think we should diverge from Hyper-V, as not signalling failure of some kind is pretty gross. If we diverge from Hyper-V, think my vote would be to inject #UD or #GP, because for all intents and purposes VMPTR{LD,ST} become unsupported instructions. E.g. diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 7ed79894d11d..e743c892eeb8 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -5888,6 +5888,12 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; + /* Forbid normal VMPTRLD if Enlightened version was used */ + if (nested_vmx_is_evmptr12_valid(vmx)) { + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; + } + if (nested_vmx_get_vmptr(vcpu, &vmptr, &r)) return r; @@ -5897,10 +5903,6 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) if (vmptr == vmx->nested.vmxon_ptr) return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER); - /* Forbid normal VMPTRLD if Enlightened version was used */ - if (nested_vmx_is_evmptr12_valid(vmx)) - return 1; - if (vmx->nested.current_vmptr != vmptr) { struct gfn_to_hva_cache *ghc = &vmx->nested.vmcs12_cache; struct vmcs_hdr hdr; @@ -5961,8 +5963,10 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; - if (unlikely(nested_vmx_is_evmptr12_valid(to_vmx(vcpu)))) + if (unlikely(nested_vmx_is_evmptr12_valid(to_vmx(vcpu)))) { + kvm_queue_exception(vcpu, UD_VECTOR); return 1; + } if (get_vmx_mem_address(vcpu, exit_qual, instr_info, true, sizeof(gpa_t), &gva))