From: sashiko-bot@kernel.org
To: "Mukesh R" <mrathor@linux.microsoft.com>
Cc: linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org
Subject: Re: [PATCH v5 8/9] mshv: Populate mmio mappings for PCI passthru
Date: Fri, 31 Jul 2026 22:54:10 +0000 [thread overview]
Message-ID: <20260731225410.E09DB1F00AC4@smtp.kernel.org> (raw)
In-Reply-To: <20260731223427.2554388-9-mrathor@linux.microsoft.com>
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
New issues:
- [Critical] Insecure MMIO region bounds check and PFN extrapolation allows mapping arbitrary host RAM into the guest.
- [Critical] Conflation of Host PFNs with Hyper-V 4KB PFNs causes arbitrary memory mapping on architectures with >4KB pages (ARM64).
- [Critical] Missing MMU interval notifier allows stale physical mappings (TOCTOU and Use-After-Unmap).
- [High] Use-After-Free of VMA pointer after dropping mmap_read_lock.
- [High] Alignment check logic error causes hypercall protocol violation for large pages.
- [High] Overloading `mmio_mfn` with `0` bypasses `page_is_ram()` checks for PFN 0.
Pre-existing issues:
- [High] Incorrect unit passed to unmap function on error path causes silent resource leak.
- [High] Unbounded O(N) `page_is_ram()` checks in process context cause CPU soft lockups.
--
--- Patch [8]: [PATCH v5 8/9] mshv: Populate mmio mappings for PCI passthru ---
commit ef68862e98379b2ba894e7946e9748f29e46d61f
Author: Mukesh R <mrathor@linux.microsoft.com>
Subject: mshv: Populate mmio mappings for PCI passthru
This commit handles hypervisor unmapped GPA intercepts by resolving the PCI
resource PFN and mapping it via hypercall. It attempts to map 2M pages where
possible to improve performance and removes broken VMA offset code.
> diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
> index cb55d4d4be2e5..4f6eb3a2aed03 100644
> --- a/drivers/hv/mshv_root_hv_call.c
> +++ b/drivers/hv/mshv_root_hv_call.c
[ ... ]
> -static int hv_do_map_gpa_hcall(u64 partition_id, u64 gfn, u64 page_struct_count,
> - u32 flags, struct page **pages, u64 mmio_spa)
> +static int hv_do_map_gpa_hcall(u64 partition_id, u64 gfn, u64 page_count,
> + u32 flags, struct page **pages, u64 mmio_mfn)
> {
[ ... ]
> - if (page_count == 0 || (pages && mmio_spa))
> - return -EINVAL;
> + if (mmio_mfn) {
> + if (pages)
> return -EINVAL;
> + for (i = 0; i < page_count; i++)
> + if (page_is_ram(mmio_mfn + i))
> + return -EINVAL;
> + }
[Severity: High]
Does this check evaluate to false when a legitimate MMIO region points to
physical PFN 0?
If mmio_mfn is 0, it appears to bypass the page_is_ram() loop entirely. Could
this allow a VMM process to map the host's physical RAM page 0 into the guest
as MMIO?
[Severity: High]
This is a pre-existing issue, but does this loop iterate over a potentially
massive number of pages without yielding?
Since page_count is derived from the user-provided region size, a maliciously
large region might force the host CPU into a soft lockup. Should we add a
cond_resched() here?
[ ... ]
> } else if (!hv_result_success(status)) {
> + pr_err("%s: failed to map pages at gfn %#llx: completed %u/%llu, flags=%#x, status=%#llx (%s)\n",
> + __func__, gfn, done, page_count, flags, status,
> + hv_result_to_string(hv_result(status)));
> ret = hv_result_to_errno(status);
> break;
> }
[Severity: High]
This is a pre-existing issue, but does the error rollback path near the end
of this function pass the wrong units to hv_call_unmap_gpa_pages()?
The variable done tracks successfully mapped large pages, but
hv_call_unmap_gpa_pages() expects its page_count argument in 4KB units. If we
pass the large page count instead, it seems like it will fail the alignment
check and silently leak dangling large page mappings in the hypervisor's
stage 2 tables.
[ ... ]
> +int hv_map_mmio_pages(u64 partition_id, struct mshv_mem_region *reg,
> + u64 mmio_mfn)
> {
[ ... ]
> + while (!HV_PAGE_COUNT_2M_ALIGNED(gfn) &&
> + !HV_PAGE_COUNT_2M_ALIGNED(mmio_mfn) &&
> + numpgs < reg->nr_pages) {
> + numpgs++;
> + gfn++;
> + mmio_mfn++;
> + }
[Severity: High]
Does the logical AND operator here cause the alignment loop to exit
prematurely?
If the offsets of gfn and mmio_mfn relative to a 2MB boundary differ, the loop
will break as soon as only one of them becomes aligned, leaving the other
unaligned.
Will this cause us to pass unaligned addresses to a large-page hypercall later
in this function, violating the Hyper-V protocol?
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index fc08e994ecdf5..b45c6b275f999 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
[ ... ]
> +static bool mshv_handle_unmapped_gpa(struct mshv_vp *vp)
> +{
[ ... ]
> + mmio_mfn = mmio_mfn - (gfn - rg->start_gfn); /* start of the range */
[Severity: Critical]
Could this backwards extrapolation yield arbitrary physical addresses if a
region spans outside its intended VMA? By extrapolating the base PFN for the
entire region backwards, it looks like it could map adjacent, unauthorized host
physical memory into the guest.
Also, on architectures with page sizes larger than 4KB (like ARM64), does this
mix incompatible units?
The function mshv_chk_get_mmio_start_pfn() returns a host PFN (e.g. 64KB
scaled), but this subtracts a 4KB-based Hyper-V GFN offset. Passing this
corrupted value to the hypervisor could cause incorrect physical addresses to
be mapped.
> +
> + /* Map the entire mmio region now. mmap lock not needed because we
> + * are just mapping GPA to static device addresses, and the above
> + * mshv_partition_region_by_gfn_get() gets a hold on the region and
> + * hence its GPA. Unmap will occur when region ref count goes to 0.
> + */
> + rc = hv_map_mmio_pages(pt->pt_id, rg, mmio_mfn);
[Severity: Critical]
Are these physical memory mappings protected against stale access?
Because MMIO regions do not register an mmu_interval_notifier, there doesn't
appear to be a mechanism to invalidate the hypervisor's translation tables if
the device is unbound or the VMA is unmapped.
Furthermore, dropping the mmap lock earlier seems to introduce a TOCTOU race
where a concurrent munmap could invalidate the PFN before the hypercall is
made. Will this allow stale mappings to persist?
> @@ -1340,7 +1424,6 @@ mshv_map_user_memory(struct mshv_partition *partition,
[ ... ]
> mmap_read_lock(current->mm);
> vma = vma_lookup(current->mm, mem->userspace_addr);
> is_mmio = vma ? !!(vma->vm_flags & (VM_IO | VM_PFNMAP)) : 0;
> - mmio_pfn = is_mmio ? vma->vm_pgoff : 0;
> mmap_read_unlock(current->mm);
>
> if (!vma)
> return -EINVAL;
>
> + if (is_mmio) {
> + size_t vma_sz = vma->vm_end - vma->vm_start;
[Severity: High]
Can this result in a use-after-free?
The vma pointer is unconditionally dereferenced here, but the lock is dropped
just above it with mmap_read_unlock(current->mm).
Could a concurrent thread in the VMM process calling munmap() unlink and
free the VMA before this calculation occurs, leading to memory corruption?
> +
> + /* Upon mmio intercept, entire region is mapped */
> + if (mem->size > vma_sz)
> + return -EPERM;
> + }
[Severity: Critical]
Does this bounds check properly validate the starting offset?
It only compares the total size against vma_sz, neglecting to check if the
region's start offset fits within the VMA. For example, it doesn't verify
that userspace_addr + size <= vm_end.
Would this allow a malicious userspace VMM to create a region that spans
outside its intended VMA?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731223427.2554388-1-mrathor@linux.microsoft.com?part=8
next prev parent reply other threads:[~2026-07-31 22:54 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 22:34 [PATCH v5 0/9] PCI passthru on Hyper-V Mukesh R
2026-07-31 22:34 ` [PATCH v5 1/9] mshv: Provide a way to get partition ID if running in a VMM process Mukesh R
2026-07-31 22:47 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 2/9] mshv: Add declarations and definitions for VFIO-MSHV bridge device Mukesh R
2026-07-31 22:42 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 3/9] mshv: Introduce basic mshv bridge device for VFIO to build upon Mukesh R
2026-07-31 22:49 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 4/9] mshv: Add ioctl support for MSHV-VFIO bridge device Mukesh R
2026-07-31 22:49 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 5/9] mshv: Import data structs around device passthru from hyperv headers Mukesh R
2026-07-31 22:45 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 6/9] PCI: hv: Export hv_build_devid_type_pci() and change return type Mukesh R
2026-07-31 22:47 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 7/9] x86/hyperv: Implement Hyper-V virtual IOMMU Mukesh R
2026-07-31 22:48 ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 8/9] mshv: Populate mmio mappings for PCI passthru Mukesh R
2026-07-31 22:54 ` sashiko-bot [this message]
2026-07-31 22:34 ` [PATCH v5 9/9] mshv: Disable movable regions upfront if device passthru Mukesh R
2026-07-31 22:57 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260731225410.E09DB1F00AC4@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mrathor@linux.microsoft.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.