mshv_prepare_pinned_region() returns 0 (success) when mshv_region_map()
fails on an unencrypted partition. The condition on the error path:
if (ret && mshv_partition_encrypted(partition))
only handles map failures for encrypted partitions — if the partition is
not encrypted and the map fails, execution falls through to 'return 0',
silently ignoring the error.
Additionally, calling mshv_region_invalidate() inline on map failure
zeroes the mreg_pages array before the caller's cleanup path
(mshv_region_destroy) can call mshv_region_unmap(). Since unmap skips
pages where mreg_pages[offset] is NULL, this can leave stale SLAT
mappings for partially-mapped pages.
Fix by returning immediately on success and falling through to error
return on failure. For unencrypted partitions, the caller's
mshv_region_destroy() handles unmap followed by invalidate in the
correct order. For encrypted partitions where re-sharing fails, zero
the page array without unpinning — the pages are inaccessible to the
host and must not be unpinned, but zeroing prevents
mshv_region_destroy() from attempting to unpin them.
Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose
/dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <[email protected]>
---
drivers/hv/mshv_root_main.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 665d565899c15..7e4252b6bc65c 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -1360,32 +1360,38 @@ static int mshv_prepare_pinned_region(struct
mshv_mem_region *region)
pt_err(partition,
"Failed to unshare memory region (guest_pfn:
%llu): %d\n",
region->start_gfn, ret);
- goto invalidate_region;
+ goto err_out;
}
}
ret = mshv_region_map(region);
- if (ret && mshv_partition_encrypted(partition)) {
+ if (ret)
+ goto share_region;
+
+ return 0;
+
+share_region:
+ if (mshv_partition_encrypted(partition)) {
int shrc;
shrc = mshv_region_share(region);
if (!shrc)
- goto invalidate_region;
+ goto err_out;
pt_err(partition,
"Failed to share memory region (guest_pfn: %llu): %d\n",
region->start_gfn, shrc);
/*
- * Don't unpin if marking shared failed because pages are no
- * longer mapped in the host, ie root, anymore.
+ * Re-sharing failed — the pages remain inaccessible to the
+ * host. Zero the page array so that mshv_region_destroy()
+ * won't attempt to unpin them (leaking the page references
+ * is intentional; unpinning host-inaccessible pages would be
+ * unsafe).
*/
+ memset(region->mreg_pages, 0,
+ region->nr_pages * sizeof(region->mreg_pages[0]));
goto err_out;
}
-
- return 0;
-
-invalidate_region:
- mshv_region_invalidate(region);
err_out:
return ret;
}