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;
 }



Reply via email to