|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 1/2] gnttab: remove guest_physmap_remove_page() call from gnttab_map_frame()
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); \
+ if ( gfn_eq(ogfn, INVALID_GFN) || gfn_eq(ogfn, gfn) || \
+ (rc_ = guest_physmap_remove_page((gt)->domain, ogfn, mfn, \
+ 0)) == 0 ) \
+ ((st) ? (gt)->arch.status_gfn \
+ : (gt)->arch.shared_gfn)[idx] = (gfn); \
+ rc_; \
+ })
#define gnttab_get_frame_gfn(gt, st, idx) ({ \
(st) ? gnttab_status_gfn(NULL, gt, idx) \
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -37,7 +37,12 @@ static inline int replace_grant_host_map
#define gnttab_init_arch(gt) 0
#define gnttab_destroy_arch(gt) do {} while ( 0 )
-#define gnttab_set_frame_gfn(gt, st, idx, gfn) do {} while ( 0 )
+#define gnttab_set_frame_gfn(gt, st, idx, gfn, mfn) \
+ (gfn_eq(gfn, INVALID_GFN) \
+ ? guest_physmap_remove_page((gt)->domain, \
+ gnttab_get_frame_gfn(gt, st, idx), \
+ mfn, 0) \
+ : 0 /* Handled in add_to_physmap_one(). */)
#define gnttab_get_frame_gfn(gt, st, idx) ({ \
mfn_t mfn_ = (st) ? gnttab_status_mfn(gt, idx) \
: gnttab_shared_mfn(gt, idx); \
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |