]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mshv: Fix create memory region overlap check
authorNuno Das Neves <nunodasneves@linux.microsoft.com>
Thu, 6 Nov 2025 22:13:30 +0000 (14:13 -0800)
committerWei Liu <wei.liu@kernel.org>
Sat, 15 Nov 2025 06:18:17 +0000 (06:18 +0000)
The current check is incorrect; it only checks if the beginning or end
of a region is within an existing region. This doesn't account for
userspace specifying a region that begins before and ends after an
existing region.

Change the logic to a range intersection check against gfns and uaddrs
for each region.

Remove mshv_partition_region_by_uaddr() as it is no longer used.

Fixes: 621191d709b1 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Reported-by: Michael Kelley <mhklinux@outlook.com>
Closes: https://lore.kernel.org/linux-hyperv/SN6PR02MB41575BE0406D3AB22E1D7DB5D4C2A@SN6PR02MB4157.namprd02.prod.outlook.com/
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
drivers/hv/mshv_root_main.c

index 7684645ef00d2761a3dc0175d8a912a8dd08630e..a8f3c5f3ce3471779ac1256994bfd9e04773cf0a 100644 (file)
@@ -1174,21 +1174,6 @@ mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn)
        return NULL;
 }
 
-static struct mshv_mem_region *
-mshv_partition_region_by_uaddr(struct mshv_partition *partition, u64 uaddr)
-{
-       struct mshv_mem_region *region;
-
-       hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) {
-               if (uaddr >= region->start_uaddr &&
-                   uaddr < region->start_uaddr +
-                           (region->nr_pages << HV_HYP_PAGE_SHIFT))
-                       return region;
-       }
-
-       return NULL;
-}
-
 /*
  * NB: caller checks and makes sure mem->size is page aligned
  * Returns: 0 with regionpp updated on success, or -errno
@@ -1198,15 +1183,21 @@ static int mshv_partition_create_region(struct mshv_partition *partition,
                                        struct mshv_mem_region **regionpp,
                                        bool is_mmio)
 {
-       struct mshv_mem_region *region;
+       struct mshv_mem_region *region, *rg;
        u64 nr_pages = HVPFN_DOWN(mem->size);
 
        /* Reject overlapping regions */
-       if (mshv_partition_region_by_gfn(partition, mem->guest_pfn) ||
-           mshv_partition_region_by_gfn(partition, mem->guest_pfn + nr_pages - 1) ||
-           mshv_partition_region_by_uaddr(partition, mem->userspace_addr) ||
-           mshv_partition_region_by_uaddr(partition, mem->userspace_addr + mem->size - 1))
+       hlist_for_each_entry(rg, &partition->pt_mem_regions, hnode) {
+               u64 rg_size = rg->nr_pages << HV_HYP_PAGE_SHIFT;
+
+               if ((mem->guest_pfn + nr_pages <= rg->start_gfn ||
+                    rg->start_gfn + rg->nr_pages <= mem->guest_pfn) &&
+                   (mem->userspace_addr + mem->size <= rg->start_uaddr ||
+                    rg->start_uaddr + rg_size <= mem->userspace_addr))
+                       continue;
+
                return -EEXIST;
+       }
 
        region = vzalloc(sizeof(*region) + sizeof(struct page *) * nr_pages);
        if (!region)