]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: x86: Take irqfds.lock when adding/deleting IRQ bypass producer
authorSean Christopherson <seanjc@google.com>
Fri, 4 Apr 2025 19:38:19 +0000 (12:38 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:28:41 +0000 (16:28 +0200)
commit f1fb088d9cecde5c3066d8ff8846789667519b7d upstream.

Take irqfds.lock when adding/deleting an IRQ bypass producer to ensure
irqfd->producer isn't modified while kvm_irq_routing_update() is running.
The only lock held when a producer is added/removed is irqbypass's mutex.

Fixes: 872768800652 ("KVM: x86: select IRQ_BYPASS_MANAGER")
Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20250404193923.1413163-5-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[sean: account for lack of kvm_x86_call()]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/x86.c

index fc2cafc33b37088e530db74ac98f90471253f128..af0b2b3bc991e26b6f8a9d4587383bc177670718 100644 (file)
@@ -13266,16 +13266,22 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
 {
        struct kvm_kernel_irqfd *irqfd =
                container_of(cons, struct kvm_kernel_irqfd, consumer);
+       struct kvm *kvm = irqfd->kvm;
        int ret;
 
-       irqfd->producer = prod;
        kvm_arch_start_assignment(irqfd->kvm);
+
+       spin_lock_irq(&kvm->irqfds.lock);
+       irqfd->producer = prod;
+
        ret = static_call(kvm_x86_pi_update_irte)(irqfd->kvm,
                                         prod->irq, irqfd->gsi, 1);
-
        if (ret)
                kvm_arch_end_assignment(irqfd->kvm);
 
+       spin_unlock_irq(&kvm->irqfds.lock);
+
+
        return ret;
 }
 
@@ -13285,9 +13291,9 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
        int ret;
        struct kvm_kernel_irqfd *irqfd =
                container_of(cons, struct kvm_kernel_irqfd, consumer);
+       struct kvm *kvm = irqfd->kvm;
 
        WARN_ON(irqfd->producer != prod);
-       irqfd->producer = NULL;
 
        /*
         * When producer of consumer is unregistered, we change back to
@@ -13295,11 +13301,17 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
         * when the irq is masked/disabled or the consumer side (KVM
         * int this case doesn't want to receive the interrupts.
        */
+       spin_lock_irq(&kvm->irqfds.lock);
+       irqfd->producer = NULL;
+
        ret = static_call(kvm_x86_pi_update_irte)(irqfd->kvm, prod->irq, irqfd->gsi, 0);
        if (ret)
                printk(KERN_INFO "irq bypass consumer (token %p) unregistration"
                       " fails: %d\n", irqfd->consumer.token, ret);
 
+       spin_unlock_irq(&kvm->irqfds.lock);
+
+
        kvm_arch_end_assignment(irqfd->kvm);
 }