On Mon, May 11, 2026 at 08:06:44AM -0700, Stanislav Kinsburskii wrote:
> On Mon, May 11, 2026 at 01:48:56PM +0000, Anirudh Rayabharam wrote:
> > On Thu, May 07, 2026 at 03:43:09PM +0000, Stanislav Kinsburskii wrote:
> > > 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.
> > 
> > mshv_region_destroy() calls mshv_region_invalidate() which calls
> > mshv_region_invalidate_pages() which just does:
> > 
> >     static void mshv_region_invalidate_pages(struct mshv_mem_region *region,
> >                                              u64 page_offset, u64 
> > page_count)
> >     {
> >             if (region->mreg_type == MSHV_REGION_TYPE_MEM_PINNED)
> >                     unpin_user_pages(region->mreg_pages + page_offset, 
> > page_count);
> > 
> >             memset(region->mreg_pages + page_offset, 0,
> >                    page_count * sizeof(struct page *));
> >     }
> > 
> > It doesn't checked for zeroed pages before unpinning.
> > 
> > > 
> > > 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).
> > >            */
> > 
> > Actually, mshv_region_destroy() also does mshv_region_share(). Maybe we
> > can remove it from here altogether. Either way, should this zeroing
> > logic be added there too so as not to crash the host by unpinning pages
> > that weren't marked shared?
> > 
> 
> Indeed.
> The issue with all this code is that we are leaking state in
> mshv_region_pin if we wimply return from it: we don't know if the pages
> are pinned or unshared (or mapped) in the destruction callback.
> We should either introduce a state variable to track this or just don't
> call the generic mshv_region_put on case of region creation error.
> The latter approch make mshv_map_user_memory idempotent and thus looks
> like a better way forward.
> What do you think?

I'm not sure I follow the latter approach. Omitting mshv_region_put()
would cause a dangling reference to the mshv_region right?

Thanks,
Anirudh.


Reply via email to