Singlestepping is enabled by setting the TF flag and care must be taken to not let the guest see (and reuse at an inconvenient time) the modified rflags value. One such case is event injection, as part of which flags are pushed on the stack to be restored later on iret. This commit disables singlestepping when we're about to inject an event and enables iret interception to still have a chance to resume our NMI injection efforts. Signed-off-by: Ladi Prosek <lprosek@xxxxxxxxxx> --- arch/x86/kvm/svm.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 739010a..c5ef56a 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3271,11 +3271,14 @@ static int cpuid_interception(struct vcpu_svm *svm) static int iret_interception(struct vcpu_svm *svm) { - ++svm->vcpu.stat.nmi_window_exits; clr_intercept(svm, INTERCEPT_IRET); - svm->vcpu.arch.hflags |= HF_IRET_MASK; - svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu); - kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); + + if (svm->vcpu.arch.hflags & HF_NMI_MASK) { + ++svm->vcpu.stat.nmi_window_exits; + svm->vcpu.arch.hflags |= HF_IRET_MASK; + svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu); + kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); + } return 1; } @@ -4823,6 +4826,22 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) if (unlikely(svm->nested.exit_required)) return; + /* + * Disable singlestep if we're injecting an interrupt/exception. + * We don't want our modified rflags to be pushed on the stack where + * we might not be able to easily reset them if we disabled NMI + * singlestep later. + */ + if (svm->nmi_singlestep && svm->vmcb->control.event_inj) { + /* + * We enabled NMI singlestepping because the NMI window was + * closed. It's unlikely that injecting another event will make + * it any better. Try again later, on next iret at the latest. + */ + disable_nmi_singlestep(svm); + set_intercept(svm, INTERCEPT_IRET); + } + pre_svm_run(svm); sync_lapic_to_cr8(vcpu); -- 2.9.3