public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] mshv: Bug fixes across the mshv_root module
@ 2026-04-29 18:17 Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 01/10] mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access Stanislav Kinsburskii
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:17 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

 This series addresses bugs found during a review of the mshv_root module
 introduced by commit 621191d709b14 ("Drivers: hv: Introduce mshv_root
 module to expose /dev/mshv to VMMs").

 The fixes range from data corruption and use-after-free to silent
 functional failures:

  - IRQ state leak and type truncation in hypercall helpers
    (hv_call_modify_spa_host_access)
  - Integer overflow on userspace-controlled allocation size
    (mshv_region_create)
  - Missing locking, broken seqcount read protection, and a check on
    uninitialized data in the irqfd path — the latter makes
    level-triggered interrupt resampling completely non-functional
  - Duplicate GSI 0 detection using the wrong predicate
  - Use-after-RCU in port ID lookup
  - Missing VP index bounds check in intercept ISR (OOB in interrupt
    context)
  - Missing error code on VP allocation failure (silent success to
    userspace)

---

Stanislav Kinsburskii (10):
      mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access
      mshv: Fix potential integer overflow in mshv_region_create
      mshv: Fix missing lock in mshv_irqfd_deassign
      mshv: Fix broken seqcount read protection
      mshv: Fix level-triggered check on uninitialized data
      mshv: Fix duplicate GSI detection for GSI 0
      mshv: Fix use-after-RCU in mshv_portid_lookup
      mshv: Use kfree_rcu in mshv_portid_free
      mshv: Add missing vp_index bounds check in intercept ISR
      mshv: Fix missing error code on VP allocation failure


 drivers/hv/mshv_eventfd.c      |   75 ++++++++++++++++++++++------------------
 drivers/hv/mshv_irq.c          |    2 +
 drivers/hv/mshv_portid_table.c |    6 +--
 drivers/hv/mshv_regions.c      |    2 +
 drivers/hv/mshv_root_hv_call.c |   18 +++-------
 drivers/hv/mshv_root_main.c    |    4 ++
 drivers/hv/mshv_synic.c        |    4 ++
 7 files changed, 59 insertions(+), 52 deletions(-)


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 01/10] mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
@ 2026-04-29 18:17 ` Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 02/10] mshv: Fix potential integer overflow in mshv_region_create Stanislav Kinsburskii
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:17 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

The bounds check inside the PFN-filling loop can return -EINVAL while
interrupts are disabled via local_irq_save(), leaking IRQ state.

Remove the check — it is redundant because the loop invariant
(done + i < page_count == page_struct_count >> large_shift) guarantees
(done + i) << large_shift < page_struct_count always holds.

While here, fix type mismatches: change 'int done' to 'u64 done' and
use u64 for loop and batch-size variables so they match the u64
page_count they are compared against.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_root_hv_call.c |   18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
index f8c2341193da5..61871ad131b4b 100644
--- a/drivers/hv/mshv_root_hv_call.c
+++ b/drivers/hv/mshv_root_hv_call.c
@@ -1041,7 +1041,7 @@ int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
 {
 	struct hv_input_modify_sparse_spa_page_host_access *input_page;
 	u64 status;
-	int done = 0;
+	u64 done = 0;
 	unsigned long irq_flags, large_shift = 0;
 	u64 page_count = page_struct_count;
 	u16 code = acquire ? HVCALL_ACQUIRE_SPARSE_SPA_PAGE_HOST_ACCESS :
@@ -1058,9 +1058,9 @@ int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
 	}
 
 	while (done < page_count) {
-		ulong i, completed, remain = page_count - done;
-		int rep_count = min(remain,
-				    HV_MODIFY_SPARSE_SPA_PAGE_HOST_ACCESS_MAX_PAGE_COUNT);
+		u64 i, completed, remain = page_count - done;
+		u64 rep_count = min_t(u64, remain,
+				      HV_MODIFY_SPARSE_SPA_PAGE_HOST_ACCESS_MAX_PAGE_COUNT);
 
 		local_irq_save(irq_flags);
 		input_page = *this_cpu_ptr(hyperv_pcpu_input_arg);
@@ -1074,15 +1074,9 @@ int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
 		input_page->flags = flags;
 		input_page->host_access = host_access;
 
-		for (i = 0; i < rep_count; i++) {
-			u64 index = (done + i) << large_shift;
-
-			if (index >= page_struct_count)
-				return -EINVAL;
-
+		for (i = 0; i < rep_count; i++)
 			input_page->spa_page_list[i] =
-						page_to_pfn(pages[index]);
-		}
+				page_to_pfn(pages[(done + i) << large_shift]);
 
 		status = hv_do_rep_hypercall(code, rep_count, 0, input_page,
 					     NULL);



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/10] mshv: Fix potential integer overflow in mshv_region_create
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 01/10] mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access Stanislav Kinsburskii
@ 2026-04-29 18:17 ` Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 03/10] mshv: Fix missing lock in mshv_irqfd_deassign Stanislav Kinsburskii
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:17 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

The allocation size is computed as:

  sizeof(*region) + sizeof(struct page *) * nr_pages

where nr_pages is a u64 originating from userspace. A sufficiently
large nr_pages can overflow the multiplication, resulting in a small
allocation followed by out-of-bounds writes when populating mreg_pages.

Use struct_size() which returns SIZE_MAX on overflow, causing vzalloc
to safely return NULL — caught by the existing error check.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_regions.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index fdffd4f002f6f..1d04a97980b8b 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -177,7 +177,7 @@ struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages,
 {
 	struct mshv_mem_region *region;
 
-	region = vzalloc(sizeof(*region) + sizeof(struct page *) * nr_pages);
+	region = vzalloc(struct_size(region, mreg_pages, nr_pages));
 	if (!region)
 		return ERR_PTR(-ENOMEM);
 



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/10] mshv: Fix missing lock in mshv_irqfd_deassign
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 01/10] mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 02/10] mshv: Fix potential integer overflow in mshv_region_create Stanislav Kinsburskii
@ 2026-04-29 18:17 ` Stanislav Kinsburskii
  2026-04-29 18:17 ` [PATCH 04/10] mshv: Fix broken seqcount read protection Stanislav Kinsburskii
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:17 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

mshv_irqfd_deactivate() and the hlist traversal of pt_irqfds_list
require pt->pt_irqfds_lock to be held, but mshv_irqfd_deassign()
omits it. This races with the EPOLLHUP path in mshv_irqfd_wakeup(),
which does take the lock before calling mshv_irqfd_deactivate().

Add the missing spin_lock_irq/spin_unlock_irq around the list
traversal, matching the pattern in mshv_irqfd_release().

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_eventfd.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c
index 90959f639dc32..704c229ee3b19 100644
--- a/drivers/hv/mshv_eventfd.c
+++ b/drivers/hv/mshv_eventfd.c
@@ -541,13 +541,14 @@ static int mshv_irqfd_deassign(struct mshv_partition *pt,
 	if (IS_ERR(eventfd))
 		return PTR_ERR(eventfd);
 
+	spin_lock_irq(&pt->pt_irqfds_lock);
 	hlist_for_each_entry_safe(irqfd, n, &pt->pt_irqfds_list,
 				  irqfd_hnode) {
 		if (irqfd->irqfd_eventfd_ctx == eventfd &&
 		    irqfd->irqfd_irqnum == args->gsi)
-
 			mshv_irqfd_deactivate(irqfd);
 	}
+	spin_unlock_irq(&pt->pt_irqfds_lock);
 
 	eventfd_ctx_put(eventfd);
 



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/10] mshv: Fix broken seqcount read protection
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (2 preceding siblings ...)
  2026-04-29 18:17 ` [PATCH 03/10] mshv: Fix missing lock in mshv_irqfd_deassign Stanislav Kinsburskii
@ 2026-04-29 18:17 ` Stanislav Kinsburskii
  2026-04-29 18:18 ` [PATCH 05/10] mshv: Fix level-triggered check on uninitialized data Stanislav Kinsburskii
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:17 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

mshv_irqfd_update() writes both irqfd_girq_ent and irqfd_lapic_irq as a
logical unit under seqcount write protection. Readers must snapshot these
fields inside the seqcount begin/retry loop to obtain a consistent
point-in-time view — otherwise a concurrent update can produce a torn
read where one field comes from the old state and the other from the new.

Both mshv_assert_irq_slow() and mshv_irqfd_wakeup() get this wrong: the
seqcount loop bodies are empty (just spinning until a stable sequence is
observed), and all reads of the protected fields happen after the loop
with no protection from concurrent writes. If mshv_irqfd_update() races
with interrupt assertion, the caller may use a stale or mixed
vector/apic_id/control combination — delivering an interrupt to the
wrong vCPU, with the wrong vector, or with the wrong trigger mode. This
can cause spurious or lost interrupts in the guest, or a stuck interrupt
line in the level-triggered case.

Fix mshv_assert_irq_slow() by snapshotting both irqfd_girq_ent and
irqfd_lapic_irq into local variables inside the seqcount loop, then
using those locals for the validity check and the hypercall.

Fix mshv_irqfd_wakeup() by snapshotting irqfd_lapic_irq inside its
seqcount loop and passing the snapshot to mshv_try_assert_irq_fast(),
so the fast path operates on the consistent copy rather than reading
the field directly outside seqcount protection.

Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_eventfd.c |   47 +++++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c
index 704c229ee3b19..d9491a14f30f1 100644
--- a/drivers/hv/mshv_eventfd.c
+++ b/drivers/hv/mshv_eventfd.c
@@ -151,10 +151,10 @@ static int mshv_vp_irq_set_vector(struct mshv_vp *vp, u32 vector)
  * Try to raise irq for guest via shared vector array. hyp does the actual
  * inject of the interrupt.
  */
-static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)
+static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd,
+				    const struct mshv_lapic_irq *irq)
 {
 	struct mshv_partition *partition = irqfd->irqfd_partn;
-	struct mshv_lapic_irq *irq = &irqfd->irqfd_lapic_irq;
 	struct mshv_vp *vp;
 
 	if (!(ms_hyperv.ext_features &
@@ -186,7 +186,8 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)
 	return 0;
 }
 #else /* CONFIG_X86_64 */
-static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)
+static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd,
+				    const struct mshv_lapic_irq *irq)
 {
 	return -EOPNOTSUPP;
 }
@@ -195,30 +196,32 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)
 static void mshv_assert_irq_slow(struct mshv_irqfd *irqfd)
 {
 	struct mshv_partition *partition = irqfd->irqfd_partn;
-	struct mshv_lapic_irq *irq = &irqfd->irqfd_lapic_irq;
+	struct mshv_guest_irq_ent girq_ent;
+	struct mshv_lapic_irq irq;
 	unsigned int seq;
 	int idx;
 
-#if IS_ENABLED(CONFIG_X86)
-	WARN_ON(irqfd->irqfd_resampler &&
-		!irq->lapic_control.level_triggered);
-#endif
-
 	idx = srcu_read_lock(&partition->pt_irq_srcu);
-	if (irqfd->irqfd_girq_ent.guest_irq_num) {
-		if (!irqfd->irqfd_girq_ent.girq_entry_valid) {
-			srcu_read_unlock(&partition->pt_irq_srcu, idx);
-			return;
-		}
 
-		do {
-			seq = read_seqcount_begin(&irqfd->irqfd_irqe_sc);
-		} while (read_seqcount_retry(&irqfd->irqfd_irqe_sc, seq));
+	do {
+		seq = read_seqcount_begin(&irqfd->irqfd_irqe_sc);
+		girq_ent = irqfd->irqfd_girq_ent;
+		irq = irqfd->irqfd_lapic_irq;
+	} while (read_seqcount_retry(&irqfd->irqfd_irqe_sc, seq));
+
+	if (girq_ent.guest_irq_num && !girq_ent.girq_entry_valid) {
+		srcu_read_unlock(&partition->pt_irq_srcu, idx);
+		return;
 	}
 
-	hv_call_assert_virtual_interrupt(irqfd->irqfd_partn->pt_id,
-					 irq->lapic_vector, irq->lapic_apic_id,
-					 irq->lapic_control);
+#if IS_ENABLED(CONFIG_X86)
+	WARN_ON(irqfd->irqfd_resampler &&
+		!irq.lapic_control.level_triggered);
+#endif
+
+	hv_call_assert_virtual_interrupt(partition->pt_id,
+					 irq.lapic_vector, irq.lapic_apic_id,
+					 irq.lapic_control);
 	srcu_read_unlock(&partition->pt_irq_srcu, idx);
 }
 
@@ -304,16 +307,18 @@ static int mshv_irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode,
 	int ret = 0;
 
 	if (flags & EPOLLIN) {
+		struct mshv_lapic_irq irq;
 		u64 cnt;
 
 		eventfd_ctx_do_read(irqfd->irqfd_eventfd_ctx, &cnt);
 		idx = srcu_read_lock(&pt->pt_irq_srcu);
 		do {
 			seq = read_seqcount_begin(&irqfd->irqfd_irqe_sc);
+			irq = irqfd->irqfd_lapic_irq;
 		} while (read_seqcount_retry(&irqfd->irqfd_irqe_sc, seq));
 
 		/* An event has been signaled, raise an interrupt */
-		ret = mshv_try_assert_irq_fast(irqfd);
+		ret = mshv_try_assert_irq_fast(irqfd, &irq);
 		if (ret)
 			mshv_assert_irq_slow(irqfd);
 



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/10] mshv: Fix level-triggered check on uninitialized data
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (3 preceding siblings ...)
  2026-04-29 18:17 ` [PATCH 04/10] mshv: Fix broken seqcount read protection Stanislav Kinsburskii
@ 2026-04-29 18:18 ` Stanislav Kinsburskii
  2026-04-29 18:18 ` [PATCH 06/10] mshv: Fix duplicate GSI detection for GSI 0 Stanislav Kinsburskii
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:18 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

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>
---
 drivers/hv/mshv_eventfd.c |   25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c
index d9491a14f30f1..fd594acce3235 100644
--- a/drivers/hv/mshv_eventfd.c
+++ b/drivers/hv/mshv_eventfd.c
@@ -478,6 +478,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) {
@@ -486,22 +499,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);
 



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/10] mshv: Fix duplicate GSI detection for GSI 0
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (4 preceding siblings ...)
  2026-04-29 18:18 ` [PATCH 05/10] mshv: Fix level-triggered check on uninitialized data Stanislav Kinsburskii
@ 2026-04-29 18:18 ` Stanislav Kinsburskii
  2026-04-29 18:18 ` [PATCH 07/10] mshv: Fix use-after-RCU in mshv_portid_lookup Stanislav Kinsburskii
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:18 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

The duplicate routing entry check in mshv_update_routing_table() uses
guest_irq_num != 0 to detect whether a GSI slot is already occupied.
This fails for GSI 0 because its guest_irq_num is 0 both when the slot
is unused (zero-initialized) and when legitimately assigned. As a
result, duplicate entries for GSI 0 are silently accepted, with the
second entry overwriting the first — corrupting the routing table
without any error reported to userspace.

While GSI 0 (legacy timer) is unlikely to appear in MSI-based routing
in practice, the check is semantically wrong — it conflates
"uninitialized" with "GSI number 0." Use girq_entry_valid instead,
which is explicitly set to true when an entry is populated and remains
zero for unused slots regardless of the GSI number.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_irq.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hv/mshv_irq.c b/drivers/hv/mshv_irq.c
index b3142c84dcbc2..65a4ffc82d566 100644
--- a/drivers/hv/mshv_irq.c
+++ b/drivers/hv/mshv_irq.c
@@ -51,7 +51,7 @@ int mshv_update_routing_table(struct mshv_partition *partition,
 		/*
 		 * Allow only one to one mapping between GSI and MSI routing.
 		 */
-		if (girq->guest_irq_num != 0) {
+		if (girq->girq_entry_valid) {
 			r = -EINVAL;
 			goto out;
 		}



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/10] mshv: Fix use-after-RCU in mshv_portid_lookup
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (5 preceding siblings ...)
  2026-04-29 18:18 ` [PATCH 06/10] mshv: Fix duplicate GSI detection for GSI 0 Stanislav Kinsburskii
@ 2026-04-29 18:18 ` Stanislav Kinsburskii
  2026-04-29 18:18 ` [PATCH 08/10] mshv: Use kfree_rcu in mshv_portid_free Stanislav Kinsburskii
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:18 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

mshv_portid_lookup() drops the RCU read lock before copying the
port_table_info struct found by idr_find(). If mshv_portid_free() runs
concurrently on another CPU, it can remove the entry and free it (via
synchronize_rcu + kfree) before the copy at line *info = *_info
completes — resulting in a use-after-free.

Move rcu_read_unlock() after the struct copy so the object remains
protected for the entire duration of the read-side access.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_portid_table.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/hv/mshv_portid_table.c b/drivers/hv/mshv_portid_table.c
index c349af1f0aaac..f1aaef69eb9b7 100644
--- a/drivers/hv/mshv_portid_table.c
+++ b/drivers/hv/mshv_portid_table.c
@@ -72,12 +72,11 @@ mshv_portid_lookup(int port_id, struct port_table_info *info)
 
 	rcu_read_lock();
 	_info = idr_find(&port_table_idr, port_id);
-	rcu_read_unlock();
-
 	if (_info) {
 		*info = *_info;
 		ret = 0;
 	}
+	rcu_read_unlock();
 
 	return ret;
 }



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/10] mshv: Use kfree_rcu in mshv_portid_free
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (6 preceding siblings ...)
  2026-04-29 18:18 ` [PATCH 07/10] mshv: Fix use-after-RCU in mshv_portid_lookup Stanislav Kinsburskii
@ 2026-04-29 18:18 ` Stanislav Kinsburskii
  2026-04-29 18:18 ` [PATCH 09/10] mshv: Add missing vp_index bounds check in intercept ISR Stanislav Kinsburskii
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:18 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

mshv_portid_free() uses synchronize_rcu() followed by kfree() to
reclaim port table entries. This blocks the caller until a full RCU
grace period elapses, which is unnecessary since the same module already
uses the non-blocking kfree_rcu() pattern in mshv_port_table_fini().

Replace with kfree_rcu() to avoid the blocking wait and keep the
reclamation strategy consistent across the file.

Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_portid_table.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/hv/mshv_portid_table.c b/drivers/hv/mshv_portid_table.c
index f1aaef69eb9b7..7ffe7a1c1e518 100644
--- a/drivers/hv/mshv_portid_table.c
+++ b/drivers/hv/mshv_portid_table.c
@@ -60,8 +60,7 @@ mshv_portid_free(int port_id)
 	WARN_ON(!info);
 	idr_unlock(&port_table_idr);
 
-	synchronize_rcu();
-	kfree(info);
+	kfree_rcu(info, portbl_rcu);
 }
 
 int



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/10] mshv: Add missing vp_index bounds check in intercept ISR
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (7 preceding siblings ...)
  2026-04-29 18:18 ` [PATCH 08/10] mshv: Use kfree_rcu in mshv_portid_free Stanislav Kinsburskii
@ 2026-04-29 18:18 ` Stanislav Kinsburskii
  2026-04-29 18:18 ` [PATCH 10/10] mshv: Fix missing error code on VP allocation failure Stanislav Kinsburskii
  2026-04-30  2:18 ` [PATCH 00/10] mshv: Bug fixes across the mshv_root module Mukesh R
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:18 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

mshv_intercept_isr() reads vp_index from the intercept message payload
and uses it directly to index into partition->pt_vp_array without
validating it against MSHV_MAX_VPS. A malformed or corrupted hypervisor
message with a vp_index beyond the array bounds would cause an
out-of-bounds memory access in interrupt context, likely crashing the
host.

Both handle_bitset_message() and handle_pair_message() already validate
vp_index before use. Add the same check to mshv_intercept_isr() for
consistency.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_synic.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c
index 43f1bcbbf2d34..5bceb81229817 100644
--- a/drivers/hv/mshv_synic.c
+++ b/drivers/hv/mshv_synic.c
@@ -384,6 +384,10 @@ mshv_intercept_isr(struct hv_message *msg)
 	 */
 	vp_index =
 	       ((struct hv_opaque_intercept_message *)msg->u.payload)->vp_index;
+	if (unlikely(vp_index >= MSHV_MAX_VPS)) {
+		pr_debug("VP index %u out of bounds\n", vp_index);
+		goto unlock_out;
+	}
 	vp = partition->pt_vp_array[vp_index];
 	if (unlikely(!vp)) {
 		pr_debug("failed to find VP %u\n", vp_index);



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/10] mshv: Fix missing error code on VP allocation failure
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (8 preceding siblings ...)
  2026-04-29 18:18 ` [PATCH 09/10] mshv: Add missing vp_index bounds check in intercept ISR Stanislav Kinsburskii
@ 2026-04-29 18:18 ` Stanislav Kinsburskii
  2026-04-30  2:18 ` [PATCH 00/10] mshv: Bug fixes across the mshv_root module Mukesh R
  10 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-29 18:18 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, longli; +Cc: linux-hyperv, linux-kernel

In mshv_partition_ioctl_create_vp(), when kzalloc for the VP struct
fails, the code jumps to the cleanup path without setting ret. At that
point ret is 0 from the preceding successful mshv_vp_stats_map() call,
so the function returns success to userspace despite having failed to
create the VP. No fd is installed and no VP is registered in pt_vp_array,
but userspace has no way to know the operation failed.

Set ret to -ENOMEM before jumping to the cleanup path.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
---
 drivers/hv/mshv_root_main.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 665d565899c15..46ebe12db9c1a 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -1186,8 +1186,10 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
 		goto unmap_ghcb_page;
 
 	vp = kzalloc_obj(*vp);
-	if (!vp)
+	if (!vp) {
+		ret = -ENOMEM;
 		goto unmap_stats_pages;
+	}
 
 	vp->vp_partition = mshv_partition_get(partition);
 	if (!vp->vp_partition) {



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 00/10] mshv: Bug fixes across the mshv_root module
  2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
                   ` (9 preceding siblings ...)
  2026-04-29 18:18 ` [PATCH 10/10] mshv: Fix missing error code on VP allocation failure Stanislav Kinsburskii
@ 2026-04-30  2:18 ` Mukesh R
  2026-04-30 14:40   ` Stanislav Kinsburskii
  10 siblings, 1 reply; 13+ messages in thread
From: Mukesh R @ 2026-04-30  2:18 UTC (permalink / raw)
  To: Stanislav Kinsburskii, kys, haiyangz, wei.liu, decui, longli
  Cc: linux-hyperv, linux-kernel

On 4/29/26 11:17, Stanislav Kinsburskii wrote:
>   This series addresses bugs found during a review of the mshv_root module
>   introduced by commit 621191d709b14 ("Drivers: hv: Introduce mshv_root
>   module to expose /dev/mshv to VMMs").
> 
>   The fixes range from data corruption and use-after-free to silent
>   functional failures:
> 
>    - IRQ state leak and type truncation in hypercall helpers
>      (hv_call_modify_spa_host_access)
>    - Integer overflow on userspace-controlled allocation size
>      (mshv_region_create)
>    - Missing locking, broken seqcount read protection, and a check on
>      uninitialized data in the irqfd path ? the latter makes
>      level-triggered interrupt resampling completely non-functional
>    - Duplicate GSI 0 detection using the wrong predicate
>    - Use-after-RCU in port ID lookup
>    - Missing VP index bounds check in intercept ISR (OOB in interrupt
>      context)
>    - Missing error code on VP allocation failure (silent success to
>      userspace)

Lot of changes here, curious, how were all these discovered
suddenly? Stress testing, internal/external?  Or reported by
copilot/sashiko/etc..

How were the fixes tested?

Thanks,
-Mukesh


> ---
> 
> Stanislav Kinsburskii (10):
>        mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access
>        mshv: Fix potential integer overflow in mshv_region_create
>        mshv: Fix missing lock in mshv_irqfd_deassign
>        mshv: Fix broken seqcount read protection
>        mshv: Fix level-triggered check on uninitialized data
>        mshv: Fix duplicate GSI detection for GSI 0
>        mshv: Fix use-after-RCU in mshv_portid_lookup
>        mshv: Use kfree_rcu in mshv_portid_free
>        mshv: Add missing vp_index bounds check in intercept ISR
>        mshv: Fix missing error code on VP allocation failure
> 
> 
>   drivers/hv/mshv_eventfd.c      |   75 ++++++++++++++++++++++------------------
>   drivers/hv/mshv_irq.c          |    2 +
>   drivers/hv/mshv_portid_table.c |    6 +--
>   drivers/hv/mshv_regions.c      |    2 +
>   drivers/hv/mshv_root_hv_call.c |   18 +++-------
>   drivers/hv/mshv_root_main.c    |    4 ++
>   drivers/hv/mshv_synic.c        |    4 ++
>   7 files changed, 59 insertions(+), 52 deletions(-)
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 00/10] mshv: Bug fixes across the mshv_root module
  2026-04-30  2:18 ` [PATCH 00/10] mshv: Bug fixes across the mshv_root module Mukesh R
@ 2026-04-30 14:40   ` Stanislav Kinsburskii
  0 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsburskii @ 2026-04-30 14:40 UTC (permalink / raw)
  To: Mukesh R
  Cc: kys, haiyangz, wei.liu, decui, longli, linux-hyperv, linux-kernel

On Wed, Apr 29, 2026 at 07:18:44PM -0700, Mukesh R wrote:
> On 4/29/26 11:17, Stanislav Kinsburskii wrote:
> >   This series addresses bugs found during a review of the mshv_root module
> >   introduced by commit 621191d709b14 ("Drivers: hv: Introduce mshv_root
> >   module to expose /dev/mshv to VMMs").
> > 
> >   The fixes range from data corruption and use-after-free to silent
> >   functional failures:
> > 
> >    - IRQ state leak and type truncation in hypercall helpers
> >      (hv_call_modify_spa_host_access)
> >    - Integer overflow on userspace-controlled allocation size
> >      (mshv_region_create)
> >    - Missing locking, broken seqcount read protection, and a check on
> >      uninitialized data in the irqfd path ? the latter makes
> >      level-triggered interrupt resampling completely non-functional
> >    - Duplicate GSI 0 detection using the wrong predicate
> >    - Use-after-RCU in port ID lookup
> >    - Missing VP index bounds check in intercept ISR (OOB in interrupt
> >      context)
> >    - Missing error code on VP allocation failure (silent success to
> >      userspace)
> 
> Lot of changes here, curious, how were all these discovered
> suddenly? Stress testing, internal/external?  Or reported by
> copilot/sashiko/etc..
> 

These are suggested by Claude Opus 4.6.

> How were the fixes tested?
> 

I ran cloud hypervisor intergration tests suite against these changes,
which covers a wide range of scenarios including interrupt handling,
memory management, and VP lifecycle.

Thanks,
Stanislav

> Thanks,
> -Mukesh
> 
> 
> > ---
> > 
> > Stanislav Kinsburskii (10):
> >        mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access
> >        mshv: Fix potential integer overflow in mshv_region_create
> >        mshv: Fix missing lock in mshv_irqfd_deassign
> >        mshv: Fix broken seqcount read protection
> >        mshv: Fix level-triggered check on uninitialized data
> >        mshv: Fix duplicate GSI detection for GSI 0
> >        mshv: Fix use-after-RCU in mshv_portid_lookup
> >        mshv: Use kfree_rcu in mshv_portid_free
> >        mshv: Add missing vp_index bounds check in intercept ISR
> >        mshv: Fix missing error code on VP allocation failure
> > 
> > 
> >   drivers/hv/mshv_eventfd.c      |   75 ++++++++++++++++++++++------------------
> >   drivers/hv/mshv_irq.c          |    2 +
> >   drivers/hv/mshv_portid_table.c |    6 +--
> >   drivers/hv/mshv_regions.c      |    2 +
> >   drivers/hv/mshv_root_hv_call.c |   18 +++-------
> >   drivers/hv/mshv_root_main.c    |    4 ++
> >   drivers/hv/mshv_synic.c        |    4 ++
> >   7 files changed, 59 insertions(+), 52 deletions(-)
> > 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-04-30 14:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29 18:17 [PATCH 00/10] mshv: Bug fixes across the mshv_root module Stanislav Kinsburskii
2026-04-29 18:17 ` [PATCH 01/10] mshv: Fix IRQ leak and type hazards in hv_call_modify_spa_host_access Stanislav Kinsburskii
2026-04-29 18:17 ` [PATCH 02/10] mshv: Fix potential integer overflow in mshv_region_create Stanislav Kinsburskii
2026-04-29 18:17 ` [PATCH 03/10] mshv: Fix missing lock in mshv_irqfd_deassign Stanislav Kinsburskii
2026-04-29 18:17 ` [PATCH 04/10] mshv: Fix broken seqcount read protection Stanislav Kinsburskii
2026-04-29 18:18 ` [PATCH 05/10] mshv: Fix level-triggered check on uninitialized data Stanislav Kinsburskii
2026-04-29 18:18 ` [PATCH 06/10] mshv: Fix duplicate GSI detection for GSI 0 Stanislav Kinsburskii
2026-04-29 18:18 ` [PATCH 07/10] mshv: Fix use-after-RCU in mshv_portid_lookup Stanislav Kinsburskii
2026-04-29 18:18 ` [PATCH 08/10] mshv: Use kfree_rcu in mshv_portid_free Stanislav Kinsburskii
2026-04-29 18:18 ` [PATCH 09/10] mshv: Add missing vp_index bounds check in intercept ISR Stanislav Kinsburskii
2026-04-29 18:18 ` [PATCH 10/10] mshv: Fix missing error code on VP allocation failure Stanislav Kinsburskii
2026-04-30  2:18 ` [PATCH 00/10] mshv: Bug fixes across the mshv_root module Mukesh R
2026-04-30 14:40   ` Stanislav Kinsburskii

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox