[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [PATCH 4/5] xen/memory: Fix acquire_resource size semantics
> -----Original Message----- > From: Xen-devel <xen-devel-bounces@xxxxxxxxxxxxxxxxxxxx> On Behalf Of Andrew > Cooper > Sent: 28 July 2020 12:37 > To: Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx> > Cc: Hubert Jasudowicz <hubert.jasudowicz@xxxxxxx>; Stefano Stabellini > <sstabellini@xxxxxxxxxx>; Julien > Grall <julien@xxxxxxx>; Wei Liu <wl@xxxxxxx>; Konrad Rzeszutek Wilk > <konrad.wilk@xxxxxxxxxx>; George > Dunlap <George.Dunlap@xxxxxxxxxxxxx>; Andrew Cooper > <andrew.cooper3@xxxxxxxxxx>; Paul Durrant > <paul@xxxxxxx>; Jan Beulich <JBeulich@xxxxxxxx>; Michał Leszczyński > <michal.leszczynski@xxxxxxx>; Ian > Jackson <ian.jackson@xxxxxxxxxx> > Subject: [PATCH 4/5] xen/memory: Fix acquire_resource size semantics > > Calling XENMEM_acquire_resource with a NULL frame_list is a request for the > size of the resource, but the returned 32 is bogus. > > If someone tries to follow it for XENMEM_resource_ioreq_server, the acquire > call will fail as IOREQ servers currently top out at 2 frames, and it is only > half the size of the default grant table limit for guests. > > Also, no users actually request a resource size, because it was never wired up > in the sole implemenation of resource aquisition in Linux. > > Introduce a new resource_max_frames() to calculate the size of a resource, and > implement it the IOREQ and grant subsystems. > > It is impossible to guarentee that a mapping call following a successful size s/guarantee/guarantee > call will succedd (e.g. The target IOREQ server gets destroyed, or the domain s/succedd/succeed > switches from grant v2 to v1). Document the restriction, and use the > flexibility to simplify the paths to be lockless. > > Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> > --- > CC: George Dunlap <George.Dunlap@xxxxxxxxxxxxx> > CC: Ian Jackson <ian.jackson@xxxxxxxxxx> > CC: Jan Beulich <JBeulich@xxxxxxxx> > CC: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> > CC: Stefano Stabellini <sstabellini@xxxxxxxxxx> > CC: Wei Liu <wl@xxxxxxx> > CC: Julien Grall <julien@xxxxxxx> > CC: Paul Durrant <paul@xxxxxxx> > CC: Michał Leszczyński <michal.leszczynski@xxxxxxx> > CC: Hubert Jasudowicz <hubert.jasudowicz@xxxxxxx> > --- > xen/arch/x86/mm.c | 20 ++++++++++++++++ > xen/common/grant_table.c | 19 +++++++++++++++ > xen/common/memory.c | 55 > +++++++++++++++++++++++++++++++++---------- > xen/include/asm-x86/mm.h | 3 +++ > xen/include/public/memory.h | 16 +++++++++---- > xen/include/xen/grant_table.h | 8 +++++++ > xen/include/xen/mm.h | 6 +++++ > 7 files changed, 110 insertions(+), 17 deletions(-) > > diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c > index 82bc676553..f73a90a2ab 100644 > --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > @@ -4600,6 +4600,26 @@ int xenmem_add_to_physmap_one( > return rc; > } > > +unsigned int arch_resource_max_frames( > + struct domain *d, unsigned int type, unsigned int id) > +{ > + unsigned int nr = 0; > + > + switch ( type ) > + { > +#ifdef CONFIG_HVM > + case XENMEM_resource_ioreq_server: > + if ( !is_hvm_domain(d) ) > + break; > + /* One frame for the buf-ioreq ring, and one frame per 128 vcpus. */ > + nr = 1 + DIV_ROUND_UP(d->max_vcpus * sizeof(struct ioreq), > PAGE_SIZE); > + break; > +#endif > + } > + > + return nr; > +} > + > int arch_acquire_resource(struct domain *d, unsigned int type, > unsigned int id, unsigned long frame, > unsigned int nr_frames, xen_pfn_t mfn_list[]) > diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c > index 122d1e7596..0962fc7169 100644 > --- a/xen/common/grant_table.c > +++ b/xen/common/grant_table.c > @@ -4013,6 +4013,25 @@ static int gnttab_get_shared_frame_mfn(struct domain > *d, > return 0; > } > > +unsigned int gnttab_resource_max_frames(struct domain *d, unsigned int id) > +{ > + unsigned int nr = 0; > + > + /* Don't need the grant lock. This limit is fixed at domain create > time. */ > + switch ( id ) > + { > + case XENMEM_resource_grant_table_id_shared: > + nr = d->grant_table->max_grant_frames; > + break; > + > + case XENMEM_resource_grant_table_id_status: > + nr = grant_to_status_frames(d->grant_table->max_grant_frames); Two uses of d->grant_table, so perhaps define a stack variable for it? Also, should you not make sure 0 is returned in the case of a v1 table? > + break; > + } > + > + return nr; > +} > + > int gnttab_acquire_resource( > struct domain *d, unsigned int id, unsigned long frame, > unsigned int nr_frames, xen_pfn_t mfn_list[]) > diff --git a/xen/common/memory.c b/xen/common/memory.c > index dc3a7248e3..21edabf9cc 100644 > --- a/xen/common/memory.c > +++ b/xen/common/memory.c > @@ -1007,6 +1007,26 @@ static long xatp_permission_check(struct domain *d, > unsigned int space) > return xsm_add_to_physmap(XSM_TARGET, current->domain, d); > } > > +/* > + * Return 0 on any kind of error. Caller converts to -EINVAL. > + * > + * All nonzero values should be repeatable (i.e. derived from some fixed > + * proerty of the domain), and describe the full resource (i.e. mapping the s/property/property > + * result of this call will be the entire resource). This precludes dynamically adding a resource to a running domain. Do we really want to bake in that restriction? > + */ > +static unsigned int resource_max_frames(struct domain *d, > + unsigned int type, unsigned int id) > +{ > + switch ( type ) > + { > + case XENMEM_resource_grant_table: > + return gnttab_resource_max_frames(d, id); > + > + default: > + return arch_resource_max_frames(d, type, id); > + } > +} > + > static int acquire_resource( > XEN_GUEST_HANDLE_PARAM(xen_mem_acquire_resource_t) arg) > { > @@ -1018,6 +1038,7 @@ static int acquire_resource( > * use-cases then per-CPU arrays or heap allocations may be required. > */ > xen_pfn_t mfn_list[32]; > + unsigned int max_frames; > int rc; > > if ( copy_from_guest(&xmar, arg, 1) ) > @@ -1026,19 +1047,6 @@ static int acquire_resource( > if ( xmar.pad != 0 ) > return -EINVAL; > > - if ( guest_handle_is_null(xmar.frame_list) ) > - { > - if ( xmar.nr_frames ) > - return -EINVAL; > - > - xmar.nr_frames = ARRAY_SIZE(mfn_list); > - > - if ( __copy_field_to_guest(arg, &xmar, nr_frames) ) > - return -EFAULT; > - > - return 0; > - } > - > if ( xmar.nr_frames > ARRAY_SIZE(mfn_list) ) > return -E2BIG; > > @@ -1050,6 +1058,27 @@ static int acquire_resource( > if ( rc ) > goto out; > > + max_frames = resource_max_frames(d, xmar.type, xmar.id); > + > + rc = -EINVAL; > + if ( !max_frames ) > + goto out; > + > + if ( guest_handle_is_null(xmar.frame_list) ) > + { > + if ( xmar.nr_frames ) > + goto out; > + > + xmar.nr_frames = max_frames; > + > + rc = -EFAULT; > + if ( __copy_field_to_guest(arg, &xmar, nr_frames) ) > + goto out; > + > + rc = 0; > + goto out; > + } > + > switch ( xmar.type ) > { > case XENMEM_resource_grant_table: > diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h > index 7e74996053..b0caf372a8 100644 > --- a/xen/include/asm-x86/mm.h > +++ b/xen/include/asm-x86/mm.h > @@ -649,6 +649,9 @@ static inline bool arch_mfn_in_directmap(unsigned long > mfn) > return mfn <= (virt_to_mfn(eva - 1) + 1); > } > > +unsigned int arch_resource_max_frames(struct domain *d, > + unsigned int type, unsigned int id); > + > int arch_acquire_resource(struct domain *d, unsigned int type, > unsigned int id, unsigned long frame, > unsigned int nr_frames, xen_pfn_t mfn_list[]); > diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h > index 21057ed78e..cea88cf40c 100644 > --- a/xen/include/public/memory.h > +++ b/xen/include/public/memory.h > @@ -639,10 +639,18 @@ struct xen_mem_acquire_resource { > #define XENMEM_resource_grant_table_id_status 1 > > /* > - * IN/OUT - As an IN parameter number of frames of the resource > - * to be mapped. However, if the specified value is 0 and > - * frame_list is NULL then this field will be set to the > - * maximum value supported by the implementation on return. > + * IN/OUT > + * > + * As an IN parameter number of frames of the resource to be mapped. > + * > + * When frame_list is NULL and nr_frames is 0, this is interpreted as a > + * request for the size of the resource, which shall be returned in the > + * nr_frames field. > + * > + * The size of a resource will never be zero, but a nonzero result > doesn't > + * guarentee that a subsequent mapping request will be successful. There s/guarantee/guarantee Paul > + * are further type/id specific constraints which may change between the > + * two calls. > */ > uint32_t nr_frames; > uint32_t pad; > diff --git a/xen/include/xen/grant_table.h b/xen/include/xen/grant_table.h > index 5a2c75b880..bae4d79623 100644 > --- a/xen/include/xen/grant_table.h > +++ b/xen/include/xen/grant_table.h > @@ -57,6 +57,8 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, > grant_ref_t ref, > int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, > mfn_t *mfn); > > +unsigned int gnttab_resource_max_frames(struct domain *d, unsigned int id); > + > int gnttab_acquire_resource( > struct domain *d, unsigned int id, unsigned long frame, > unsigned int nr_frames, xen_pfn_t mfn_list[]); > @@ -93,6 +95,12 @@ static inline int gnttab_map_frame(struct domain *d, > unsigned long idx, > return -EINVAL; > } > > +static inline unsigned int gnttab_resource_max_frames( > + struct domain *d, unsigned int id) > +{ > + return 0; > +} > + > static inline int gnttab_acquire_resource( > struct domain *d, unsigned int id, unsigned long frame, > unsigned int nr_frames, xen_pfn_t mfn_list[]) > diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h > index 1b2c1f6b32..c184dc1db1 100644 > --- a/xen/include/xen/mm.h > +++ b/xen/include/xen/mm.h > @@ -686,6 +686,12 @@ static inline void put_page_alloc_ref(struct page_info > *page) > } > > #ifndef CONFIG_ARCH_ACQUIRE_RESOURCE > +static inline unsigned int arch_resource_max_frames( > + struct domain *d, unsigned int type, unsigned int id) > +{ > + return 0; > +} > + > static inline int arch_acquire_resource( > struct domain *d, unsigned int type, unsigned int id, unsigned long > frame, > unsigned int nr_frames, xen_pfn_t mfn_list[]) > -- > 2.11.0 >
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |