mshv: Fix create memory region overlap check

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: 621191d709 ("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>
This commit is contained in:
Nuno Das Neves 2025-11-06 14:13:30 -08:00 committed by Wei Liu
parent 8ec6070fc8
commit ba9eb9b86d

View 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)