[PATCH v2] KVM: x86: accept userspace interrupt only if no event is injected

From: Paolo Bonzini
Date: Tue Jul 27 2021 - 13:06:31 EST


Once an exception has been injected, any side effects related to
the exception (such as setting CR2 or DR6) have been taked place.
Therefore, once KVM sets the VM-entry interruption information
field or the AMD EVENTINJ field, the next VM-entry must deliver that
exception.

Pending interrupts are processed after injected exceptions, so
in theory it would not be a problem to use KVM_INTERRUPT when
an injected exception is present. However, DOSEMU is using
run->ready_for_interrupt_injection to detect interrupt windows
and then using KVM_SET_SREGS/KVM_SET_REGS to inject the
interrupt manually. For this to work, the interrupt window
must be delayed after the completion of the previous event
injection.

Cc: stable@xxxxxxxxxxxxxxx
Reported-by: Stas Sergeev <stsp2@xxxxxxxxx>
Tested-by: Stas Sergeev <stsp2@xxxxxxxxx>
Fixes: 71cc849b7093 ("KVM: x86: Fix split-irqchip vs interrupt injection window request")
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
(cherry picked from commit 043264d97e9ab74cc9661c8b1f9c00c8ce24cad9)
---
arch/x86/kvm/x86.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4116567f3d44..5e921f1e00db 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4358,8 +4358,18 @@ static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)

static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)
{
+ /*
+ * Do not cause an interrupt window exit if an exception
+ * is pending or an event needs reinjection; userspace
+ * might want to inject the interrupt manually using KVM_SET_REGS
+ * or KVM_SET_SREGS. For that to work, we must be at an
+ * instruction boundary and with no events half-injected.
+ */
return kvm_arch_interrupt_allowed(vcpu) &&
- kvm_cpu_accept_dm_intr(vcpu);
+ kvm_cpu_accept_dm_intr(vcpu) &&
+ !kvm_event_needs_reinjection(vcpu)
+ !vcpu->arch.exception.pending;
+
}

static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
--
2.27.0