mshv_partition_create_region() checks for overlapping guest memory
regions using arithmetic that can overflow u64:
mem->guest_pfn + nr_pages <= rg->start_gfn
If guest_pfn is near U64_MAX, the addition wraps around to a small
value, causing the overlap check to incorrectly pass. This could allow
creation of overlapping regions.
Fix by validating the sum with check_add_overflow() before the loop and
using the pre-computed end_gfn in the comparison.
Fixes: f91bc8f61abf ("mshv: Allow mappings that overlap in uaddr")
Signed-off-by: Stanislav Kinsburskii <[email protected]>
---
drivers/hv/mshv_root_main.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index aa0f452aa17c1..2b7d56e108bad 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -1290,11 +1290,15 @@ static int mshv_partition_create_region(struct
mshv_partition *partition,
{
struct mshv_mem_region *rg;
u64 nr_pages = HVPFN_DOWN(mem->size);
+ u64 end_gfn;
+
+ if (check_add_overflow(mem->guest_pfn, nr_pages, &end_gfn))
+ return -EINVAL;
/* Reject overlapping regions */
spin_lock(&partition->pt_mem_regions_lock);
hlist_for_each_entry(rg, &partition->pt_mem_regions, hnode) {
- if (mem->guest_pfn + nr_pages <= rg->start_gfn ||
+ if (end_gfn <= rg->start_gfn ||
rg->start_gfn + rg->nr_pages <= mem->guest_pfn)
continue;
spin_unlock(&partition->pt_mem_regions_lock);