* [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