[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 1/2] gnttab: remove guest_physmap_remove_page() call from gnttab_map_frame()
On Mon, Sep 13, 2021 at 08:41:47AM +0200, Jan Beulich wrote: > Without holding appropriate locks, attempting to remove a prior mapping > of the underlying page is pointless, as the same (or another) mapping > could be re-established by a parallel request on another vCPU. Move the > code to Arm's gnttab_set_frame_gfn(). Of course this new placement > doesn't improve things in any way as far as the security of grant status > frame mappings goes (see XSA-379). Proper locking would be needed here > to allow status frames to be mapped securely. > > In turn this then requires replacing the other use in > gnttab_unpopulate_status_frames(), which yet in turn requires adjusting > x86's gnttab_set_frame_gfn(). Note that with proper locking inside > guest_physmap_remove_page() combined with checking the GFN's mapping > there against the passed in MFN, there then is no issue with the > involved multiple gnttab_set_frame_gfn()-s potentially returning varying > values (due to a racing XENMAPSPACE_grant_table request). > > This, as a side effect, does away with gnttab_map_frame() having a local > variable "gfn" which shadows a function parameter of the same name. > > Together with XSA-379 this points out that XSA-255's addition to > gnttab_map_frame() was really useless. > > Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> > > --- a/xen/common/grant_table.c > +++ b/xen/common/grant_table.c > @@ -92,7 +92,7 @@ struct grant_table { > struct radix_tree_root maptrack_tree; > > /* Domain to which this struct grant_table belongs. */ > - const struct domain *domain; > + struct domain *domain; > > struct grant_table_arch arch; > }; > @@ -1795,8 +1795,8 @@ gnttab_unpopulate_status_frames(struct d > { > int rc = gfn_eq(gfn, INVALID_GFN) > ? 0 > - : guest_physmap_remove_page(d, gfn, > - page_to_mfn(pg), 0); > + : gnttab_set_frame_gfn(gt, true, i, INVALID_GFN, > + page_to_mfn(pg)); > > if ( rc ) > { > @@ -1806,7 +1806,6 @@ gnttab_unpopulate_status_frames(struct d > domain_crash(d); > return rc; > } > - gnttab_set_frame_gfn(gt, true, i, INVALID_GFN); > } > > BUG_ON(page_get_owner(pg) != d); > @@ -4132,6 +4131,9 @@ int gnttab_map_frame(struct domain *d, u > struct grant_table *gt = d->grant_table; > bool status = false; > > + if ( gfn_eq(gfn, INVALID_GFN) ) > + return -EINVAL; > + > grant_write_lock(gt); > > if ( evaluate_nospec(gt->gt_version == 2) && (idx & > XENMAPIDX_grant_table_status) ) > @@ -4144,24 +4146,18 @@ int gnttab_map_frame(struct domain *d, u > else > rc = gnttab_get_shared_frame_mfn(d, idx, mfn); > > - if ( !rc && paging_mode_translate(d) ) > - { > - gfn_t gfn = gnttab_get_frame_gfn(gt, status, idx); > - > - if ( !gfn_eq(gfn, INVALID_GFN) ) > - rc = guest_physmap_remove_page(d, gfn, *mfn, 0); > - } > - > if ( !rc ) > { > + struct page_info *pg = mfn_to_page(*mfn); > + > /* > * Make sure gnttab_unpopulate_status_frames() won't (successfully) > * free the page until our caller has completed its operation. > */ > - if ( get_page(mfn_to_page(*mfn), d) ) > - gnttab_set_frame_gfn(gt, status, idx, gfn); > - else > + if ( !get_page(pg, d) ) > rc = -EBUSY; > + else if ( (rc = gnttab_set_frame_gfn(gt, status, idx, gfn, *mfn)) ) > + put_page(pg); > } > > grant_write_unlock(gt); > --- a/xen/include/asm-arm/grant_table.h > +++ b/xen/include/asm-arm/grant_table.h > @@ -71,11 +71,17 @@ int replace_grant_host_mapping(unsigned > XFREE((gt)->arch.status_gfn); \ > } while ( 0 ) > > -#define gnttab_set_frame_gfn(gt, st, idx, gfn) \ > - do { \ > - ((st) ? (gt)->arch.status_gfn : (gt)->arch.shared_gfn)[idx] = \ > - (gfn); \ > - } while ( 0 ) > +#define gnttab_set_frame_gfn(gt, st, idx, gfn, mfn) \ > + ({ \ > + int rc_ = 0; \ > + gfn_t ogfn = gnttab_get_frame_gfn(gt, st, idx); \ Newline maybe? Not sure whether we decided that macros should also follow coding style regarding variable definition followed by newline. > + if ( gfn_eq(ogfn, INVALID_GFN) || gfn_eq(ogfn, gfn) || \ I'm slightly confused by this checks, don't you need to check for gfn_eq(gfn, INVALID_GFN) (not ogfn) in order to call guest_physmap_remove_page? Or assuming that ogfn is not invalid can be used to imply a removal? Also the check for ogfn == gfn is only used on Arm, while I would assume a similar one would be needed on x86 to guarantee the same behavior? Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |