kvm_check_and_inject_events() checks for a pending PIC interrupt using kvm_cpu_has_injectable_intr() and then fetches it using kvm_cpu_get_interrupt(). These two operations are not atomic with respect to vpic->output. Between the check and fetch, another thread running on a different CPU can call kvm_pic_read_irq() which sets output=0 before taking pic_lock(), making it immediately visible to all other threads: Thread A: kvm_cpu_has_injectable_intr() reads output=1 Thread B: kvm_pic_read_irq() sets output=0 before lock Thread A: kvm_cpu_get_interrupt() reads output=0 Thread A: returns -1, WARN_ON_ONCE fires The -1 return is a valid result indicating another thread already consumed the interrupt between the check and fetch. Replace WARN_ON_ONCE with a graceful goto out to handle this race condition correctly. Reported-by: syzbot+9dcd0a11dc9703a49511@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=9dcd0a11dc9703a49511 Signed-off-by: Deepanshu Kartikey --- arch/x86/kvm/x86.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index afcac1042947..36bf479a1164 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10797,11 +10797,11 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, if (r) { int irq = kvm_cpu_get_interrupt(vcpu); - if (!WARN_ON_ONCE(irq == -1)) { - kvm_queue_interrupt(vcpu, irq, false); - kvm_x86_call(inject_irq)(vcpu, false); - WARN_ON(kvm_x86_call(interrupt_allowed)(vcpu, true) < 0); - } + if (irq == -1) + goto out; + kvm_queue_interrupt(vcpu, irq, false); + kvm_x86_call(inject_irq)(vcpu, false); + WARN_ON(kvm_x86_call(interrupt_allowed)(vcpu, true) < 0); } if (kvm_cpu_has_injectable_intr(vcpu)) kvm_x86_call(enable_irq_window)(vcpu); -- 2.43.0