[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 4/4] xen/version: Introduce non-truncating XENVER_* subops
On 03.01.2023 21:09, 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. Which is fine as long as only ASCII is returned. If non-ASCII can be returned, I agree "unsigned char" is better, but then we also need to spell out what encoding the strings use (UTF-8 presumably). > API/ABI wise, XENVER_build_id could be merged into xenver_varstring_op(), but > the internal infrastructure is awkward. I guess build-id also doesn't fit the rest because of not returning strings, but indeed an array of bytes. You also couldn't use strlen() on the array. > @@ -469,6 +470,66 @@ static int __init cf_check param_init(void) > __initcall(param_init); > #endif > > +static long xenver_varstring_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) > +{ > + const char *str = NULL; > + size_t sz = 0; > + union { > + xen_capabilities_info_t info; > + } u; > + struct xen_var_string user_str; > + > + 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: > + memset(u.info, 0, sizeof(u.info)); > + arch_get_xen_caps(&u.info); > + str = u.info; > + break; > + > + default: > + ASSERT_UNREACHABLE(); > + break; > + } > + > + if ( !str || > + !(sz = strlen(str)) ) > + return -ENODATA; /* failsafe */ Is this really appropriate for e.g. an empty command line? > + if ( sz > INT32_MAX ) > + return -E2BIG; /* Compat guests. 2G ought to be plenty. */ While the comment here and in the public header mention compat guests, the check is uniform. What's the deal? > + 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_var_string, buf), > + str, sz) ) > + return -EFAULT; Not inserting a nul terminator is going to make this slightly awkward to use. > @@ -103,6 +126,35 @@ struct xen_build_id { > }; > typedef struct xen_build_id xen_build_id_t; > > +/* > + * Container for an arbitrary variable length string. > + */ > +struct xen_var_string { > + uint32_t len; /* IN: size of buf[] in bytes. */ > + unsigned char buf[XEN_FLEX_ARRAY_DIM]; /* OUT: requested data. */ > +}; > +typedef struct xen_var_string xen_var_string_t; > + > +/* > + * arg == xenver_string_t Nit: xen_var_string_t (also again in the following text). > + * Equivalent to the original ops, but with a non-truncating API/ABI. > + * > + * Passing arg == NULL is a request for size. The returned size does not > + * include a NUL terminator, and has a practical upper limit of INT32_MAX for > + * 32bit guests. This is expected to be plenty for the purpose. As said above, the limit applies to all guests, which the wording here doesn't suggest. Jan > + * Otherwise, the input xenver_string_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). > + * > + * These hypercalls can fail, in which case they'll return -XEN_Exx. > + */ > +#define XENVER_extraversion2 11 > +#define XENVER_capabilities2 12 > +#define XENVER_changeset2 13 > +#define XENVER_commandline2 14 > + > #endif /* __XEN_PUBLIC_VERSION_H__ */ > > /*
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |