]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mshv: Fix level-triggered check on uninitialized data
authorStanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Thu, 7 May 2026 15:43:43 +0000 (15:43 +0000)
committerWei Liu <wei.liu@kernel.org>
Fri, 31 Jul 2026 20:01:57 +0000 (20:01 +0000)
In mshv_irqfd_assign(), the level-triggered validation for resample
irqfds checks irqfd_lapic_irq.lapic_control.level_triggered before
mshv_irqfd_update() has populated the field. Since the irqfd struct is
zero-allocated, level_triggered is always 0 at that point, causing the
check to always reject resample irqfds with -EINVAL. This makes
level-triggered interrupt resampling — used to avoid interrupt storms
with assigned devices — completely non-functional.

Move the check after the mshv_irqfd_update() call, which resolves the
IRQ routing entry and populates irqfd_lapic_irq with the actual trigger
mode.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Reviewed-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
drivers/hv/mshv_eventfd.c

index 5995a62aff8d8df05918113607aaa49746c8f602..047e5bd432381e750826165f03eaedb4dc1d08a1 100644 (file)
@@ -473,6 +473,19 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
        init_poll_funcptr(&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc);
 
        spin_lock_irq(&pt->pt_irqfds_lock);
+       ret = 0;
+       hlist_for_each_entry(tmp, &pt->pt_irqfds_list, irqfd_hnode) {
+               if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx)
+                       continue;
+               /* This fd is used for another irq already. */
+               ret = -EBUSY;
+               spin_unlock_irq(&pt->pt_irqfds_lock);
+               goto fail;
+       }
+
+       idx = srcu_read_lock(&pt->pt_irq_srcu);
+       mshv_irqfd_update(pt, irqfd);
+
 #if IS_ENABLED(CONFIG_X86)
        if (args->flags & BIT(MSHV_IRQFD_BIT_RESAMPLE) &&
            !irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {
@@ -481,22 +494,12 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
                 * Otherwise return with failure
                 */
                spin_unlock_irq(&pt->pt_irqfds_lock);
+               srcu_read_unlock(&pt->pt_irq_srcu, idx);
                ret = -EINVAL;
                goto fail;
        }
 #endif
-       ret = 0;
-       hlist_for_each_entry(tmp, &pt->pt_irqfds_list, irqfd_hnode) {
-               if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx)
-                       continue;
-               /* This fd is used for another irq already. */
-               ret = -EBUSY;
-               spin_unlock_irq(&pt->pt_irqfds_lock);
-               goto fail;
-       }
 
-       idx = srcu_read_lock(&pt->pt_irq_srcu);
-       mshv_irqfd_update(pt, irqfd);
        hlist_add_head(&irqfd->irqfd_hnode, &pt->pt_irqfds_list);
        spin_unlock_irq(&pt->pt_irqfds_lock);