Skip to content

Commit

Permalink
KVM: VMX: Refresh available regs and IDT vectoring info before NMI ha…
Browse files Browse the repository at this point in the history
…ndling

commit 50011c2 upstream.

Reset the mask of available "registers" and refresh the IDT vectoring
info snapshot in vmx_vcpu_enter_exit(), before KVM potentially handles a
an NMI VM-Exit.  One of the "registers" that KVM VMX lazily loads is the
vmcs.VM_EXIT_INTR_INFO field, which is holds the vector+type on "exception
or NMI" VM-Exits, i.e. is needed to identify NMIs.  Clearing the available
registers bitmask after handling NMIs results in KVM querying info from
the last VM-Exit that read vmcs.VM_EXIT_INTR_INFO, and leads to both
missed NMIs and spurious NMIs in the host.

Opportunistically grab vmcs.IDT_VECTORING_INFO_FIELD early in the VM-Exit
path too, e.g. to guard against similar consumption of stale data.  The
field is read on every "normal" VM-Exit, and there's no point in delaying
the inevitable.

Reported-by: Like Xu <like.xu.linux@gmail.com>
Fixes: 11df586 ("KVM: VMX: Handle NMI VM-Exits in noinstr region")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20230825014532.2846714-1-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
sean-jc authored and gregkh committed Sep 19, 2023
1 parent 240713e commit c6b4258
Showing 1 changed file with 11 additions and 10 deletions.
21 changes: 11 additions & 10 deletions arch/x86/kvm/vmx/vmx.c
Expand Up @@ -7243,13 +7243,20 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
flags);

vcpu->arch.cr2 = native_read_cr2();
vcpu->arch.regs_avail &= ~VMX_REGS_LAZY_LOAD_SET;

vmx->idt_vectoring_info = 0;

vmx_enable_fb_clear(vmx);

if (unlikely(vmx->fail))
if (unlikely(vmx->fail)) {
vmx->exit_reason.full = 0xdead;
else
vmx->exit_reason.full = vmcs_read32(VM_EXIT_REASON);
goto out;
}

vmx->exit_reason.full = vmcs_read32(VM_EXIT_REASON);
if (likely(!vmx->exit_reason.failed_vmentry))
vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);

if ((u16)vmx->exit_reason.basic == EXIT_REASON_EXCEPTION_NMI &&
is_nmi(vmx_get_intr_info(vcpu))) {
Expand All @@ -7258,6 +7265,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
kvm_after_interrupt(vcpu);
}

out:
guest_state_exit_irqoff();
}

Expand Down Expand Up @@ -7379,8 +7387,6 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
loadsegment(es, __USER_DS);
#endif

vcpu->arch.regs_avail &= ~VMX_REGS_LAZY_LOAD_SET;

pt_guest_exit(vmx);

kvm_load_host_xsave_state(vcpu);
Expand All @@ -7397,17 +7403,12 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
vmx->nested.nested_run_pending = 0;
}

vmx->idt_vectoring_info = 0;

if (unlikely(vmx->fail))
return EXIT_FASTPATH_NONE;

if (unlikely((u16)vmx->exit_reason.basic == EXIT_REASON_MCE_DURING_VMENTRY))
kvm_machine_check();

if (likely(!vmx->exit_reason.failed_vmentry))
vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);

trace_kvm_exit(vcpu, KVM_ISA_VMX);

if (unlikely(vmx->exit_reason.failed_vmentry))
Expand Down

0 comments on commit c6b4258

Please sign in to comment.