[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 02/10] xen/version: Introduce non-truncating deterministically-signed XENVER_* subops
Hi everyone following this thread, please see: https://marc.info/?l=xen-devel&m=170135718323946 https://cryptpad.fr/form/#/2/form/view/7ByH95Vd7KiDOvN4wjV5iUGlMuZbkVdwk7cYpZdluWo/ For a vote on the usage of the word "broken" On Tue, 15 Aug 2023, Andrew Cooper wrote: > Recently in XenServer, we have encountered problems caused by both > XENVER_extraversion and XENVER_commandline having fixed bounds. > > More than just the invariant size, the APIs/ABIs also broken by typedef-ing an > array, and using an unqualified 'char' which has implementation-specific > signed-ness. > > Provide brand new ops, which are capable of expressing variable length > strings, and mark the older ops as broken. > > This fixes all issues around XENVER_extraversion being longer than 15 chars. > Further work beyond just this API is needed to remove other assumptions about > XENVER_commandline being 1023 chars long. > > Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> > Reviewed-by: Jason Andryuk <jandryuk@xxxxxxxxx> > --- > CC: George Dunlap <George.Dunlap@xxxxxxxxxxxxx> > CC: Jan Beulich <JBeulich@xxxxxxxx> > CC: Stefano Stabellini <sstabellini@xxxxxxxxxx> > CC: Wei Liu <wl@xxxxxxx> > CC: Julien Grall <julien@xxxxxxx> > CC: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> > CC: Daniel Smith <dpsmith@xxxxxxxxxxxxxxxxxxxx> > CC: Jason Andryuk <jandryuk@xxxxxxxxx> > CC: Henry Wang <Henry.Wang@xxxxxxx> > > v3: > * Modify dummy.h's xsm_xen_version() in the same way as flask. > v2: > * Remove xen_capabilities_info_t from the stack now that arch_get_xen_caps() > has gone. > * Use an arbitrary limit check much lower than INT_MAX. > * Use "buf" rather than "string" terminology. > * Expand the API comment. > > Tested by forcing XENVER_extraversion to be 20 chars long, and confirming that > an untruncated version can be obtained. > --- > xen/common/kernel.c | 62 +++++++++++++++++++++++++++++++++++ > xen/include/public/version.h | 63 ++++++++++++++++++++++++++++++++++-- > xen/include/xlat.lst | 1 + > xen/include/xsm/dummy.h | 3 ++ > xen/xsm/flask/hooks.c | 4 +++ > 5 files changed, 131 insertions(+), 2 deletions(-) > > diff --git a/xen/common/kernel.c b/xen/common/kernel.c > index f822480a8ef3..79c008c7ee5f 100644 > --- a/xen/common/kernel.c > +++ b/xen/common/kernel.c > @@ -24,6 +24,7 @@ > CHECK_build_id; > CHECK_compile_info; > CHECK_feature_info; > +CHECK_varbuf; > #endif > > enum system_state system_state = SYS_STATE_early_boot; > @@ -498,6 +499,59 @@ static int __init cf_check param_init(void) > __initcall(param_init); > #endif > > +static long xenver_varbuf_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) > +{ > + struct xen_varbuf user_str; > + const char *str = NULL; > + size_t sz; > + > + switch ( cmd ) > + { > + case XENVER_extraversion2: > + str = xen_extra_version(); > + break; > + > + case XENVER_changeset2: > + str = xen_changeset(); > + break; > + > + case XENVER_commandline2: > + str = saved_cmdline; > + break; > + > + case XENVER_capabilities2: > + str = xen_cap_info; > + break; > + > + default: > + ASSERT_UNREACHABLE(); > + return -ENODATA; > + } > + > + sz = strlen(str); > + > + if ( sz > KB(64) ) /* Arbitrary limit. Avoid long-running operations. */ > + return -E2BIG; > + > + if ( guest_handle_is_null(arg) ) /* Length request */ > + return sz; > + > + if ( copy_from_guest(&user_str, arg, 1) ) > + return -EFAULT; > + > + if ( user_str.len == 0 ) > + return -EINVAL; > + > + if ( sz > user_str.len ) > + return -ENOBUFS; > + > + if ( copy_to_guest_offset(arg, offsetof(struct xen_varbuf, buf), > + str, sz) ) > + return -EFAULT; > + > + return sz; > +} > + > long do_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) > { > bool_t deny = !!xsm_xen_version(XSM_OTHER, cmd); > @@ -711,6 +765,14 @@ long do_xen_version(int cmd, > XEN_GUEST_HANDLE_PARAM(void) arg) > > return sz; > } > + > + case XENVER_extraversion2: > + case XENVER_capabilities2: > + case XENVER_changeset2: > + case XENVER_commandline2: > + if ( deny ) > + return -EPERM; > + return xenver_varbuf_op(cmd, arg); > } > > return -ENOSYS; > diff --git a/xen/include/public/version.h b/xen/include/public/version.h > index cbc4ef7a46e6..0dd6bbcb43cc 100644 > --- a/xen/include/public/version.h > +++ b/xen/include/public/version.h > @@ -19,12 +19,20 @@ > /* arg == NULL; returns major:minor (16:16). */ > #define XENVER_version 0 > > -/* arg == xen_extraversion_t. */ > +/* > + * arg == xen_extraversion_t. > + * > + * This API/ABI is broken. Use XENVER_extraversion2 where possible. > + */ > #define XENVER_extraversion 1 > typedef char xen_extraversion_t[16]; > #define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t)) > > -/* arg == xen_compile_info_t. */ > +/* > + * arg == xen_compile_info_t. > + * > + * This API/ABI is broken and truncates data. > + */ > #define XENVER_compile_info 2 > struct xen_compile_info { > char compiler[64]; > @@ -34,10 +42,20 @@ struct xen_compile_info { > }; > typedef struct xen_compile_info xen_compile_info_t; > > +/* > + * arg == xen_capabilities_info_t. > + * > + * This API/ABI is broken. Use XENVER_capabilities2 where possible. > + */ > #define XENVER_capabilities 3 > typedef char xen_capabilities_info_t[1024]; > #define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t)) > > +/* > + * arg == xen_changeset_info_t. > + * > + * This API/ABI is broken. Use XENVER_changeset2 where possible. > + */ > #define XENVER_changeset 4 > typedef char xen_changeset_info_t[64]; > #define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t)) > @@ -95,6 +113,11 @@ typedef struct xen_feature_info xen_feature_info_t; > */ > #define XENVER_guest_handle 8 > > +/* > + * arg == xen_commandline_t. > + * > + * This API/ABI is broken. Use XENVER_commandline2 where possible. > + */ > #define XENVER_commandline 9 > typedef char xen_commandline_t[1024]; > > @@ -110,6 +133,42 @@ struct xen_build_id { > }; > typedef struct xen_build_id xen_build_id_t; > > +/* > + * Container for an arbitrary variable length buffer. > + */ > +struct xen_varbuf { > + uint32_t len; /* IN: size of buf[] in bytes. */ > + unsigned char buf[XEN_FLEX_ARRAY_DIM]; /* OUT: requested data. */ > +}; > +typedef struct xen_varbuf xen_varbuf_t; > + > +/* > + * arg == xen_varbuf_t > + * > + * Equivalent to the original ops, but with a non-truncating API/ABI. > + * > + * These hypercalls can fail for a number of reasons. All callers must > handle > + * -XEN_xxx return values appropriately. > + * > + * Passing arg == NULL is a request for size, which will be signalled with a > + * non-negative return value. Note: a return size of 0 may be legitimate for > + * the requested subop. > + * > + * Otherwise, the input xen_varbuf_t provides the size of the following > + * buffer. Xen will fill the buffer, and return the number of bytes written > + * (e.g. if the input buffer was longer than necessary). > + * > + * Some subops may return binary data. Some subops may be expected to return > + * textural data. These are returned without a NUL terminator, and while the > + * contents is expected to be ASCII/UTF-8, Xen makes no guarentees to this > + * effect. e.g. Xen has no control over the formatting used for the command > + * line. > + */ > +#define XENVER_extraversion2 11 > +#define XENVER_capabilities2 12 > +#define XENVER_changeset2 13 > +#define XENVER_commandline2 14 > + > #endif /* __XEN_PUBLIC_VERSION_H__ */ > > /* > diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst > index 9c41948514bf..a61ba85ed0ca 100644 > --- a/xen/include/xlat.lst > +++ b/xen/include/xlat.lst > @@ -173,6 +173,7 @@ > ? build_id version.h > ? compile_info version.h > ? feature_info version.h > +? varbuf version.h > ? xenoprof_init xenoprof.h > ? xenoprof_passive xenoprof.h > ? flask_access xsm/flask_op.h > diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h > index 8671af1ba4d3..a4a920f74e6e 100644 > --- a/xen/include/xsm/dummy.h > +++ b/xen/include/xsm/dummy.h > @@ -828,9 +828,12 @@ static XSM_INLINE int cf_check > xsm_xen_version(XSM_DEFAULT_ARG uint32_t op) > block_speculation(); > return 0; > case XENVER_extraversion: > + case XENVER_extraversion2: > case XENVER_compile_info: > case XENVER_capabilities: > + case XENVER_capabilities2: > case XENVER_changeset: > + case XENVER_changeset2: > case XENVER_pagesize: > case XENVER_guest_handle: > /* These MUST always be accessible to any guest by default. */ > diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c > index 78225f68c15c..a671dcd0322e 100644 > --- a/xen/xsm/flask/hooks.c > +++ b/xen/xsm/flask/hooks.c > @@ -1777,15 +1777,18 @@ static int cf_check flask_xen_version(uint32_t op) > /* These sub-ops ignore the permission checks and return data. */ > return 0; > case XENVER_extraversion: > + case XENVER_extraversion2: > return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_VERSION, > VERSION__XEN_EXTRAVERSION, NULL); > case XENVER_compile_info: > return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_VERSION, > VERSION__XEN_COMPILE_INFO, NULL); > case XENVER_capabilities: > + case XENVER_capabilities2: > return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_VERSION, > VERSION__XEN_CAPABILITIES, NULL); > case XENVER_changeset: > + case XENVER_changeset2: > return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_VERSION, > VERSION__XEN_CHANGESET, NULL); > case XENVER_pagesize: > @@ -1795,6 +1798,7 @@ static int cf_check flask_xen_version(uint32_t op) > return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_VERSION, > VERSION__XEN_GUEST_HANDLE, NULL); > case XENVER_commandline: > + case XENVER_commandline2: > return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_VERSION, > VERSION__XEN_COMMANDLINE, NULL); > case XENVER_build_id: > -- > 2.30.2 >
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |