[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v2 1/7] lib/uklibparam: Introduce the library parameter
Hi Sharan and Felipe, I have a suggestion, please see inline. On 8/15/19 1:48 PM, Felipe Huici wrote: > Hi Sharan, > > Thanks for fixing the extensive list of comments from Florian. There are > still cases where providing maliciously-formatted strings (e.g., > test.testarr2=\"'''''''''''''''''''\"\"\"wef238@#*(@#\") causes unexpected > behavior, but I'm satisfied that the code can handle most common typos/errors > -- we're not trying to be robust to intentionally malicious behavior. > > I have one more minor comment inline. > > -- Felipe > > On 13.08.19, 14:37, "Minios-devel on behalf of Sharan Santhanam" > <minios-devel-bounces@xxxxxxxxxxxxxxxxxxxx on behalf of > Sharan.Santhanam@xxxxxxxxx> wrote: > > This patch provides the header necessary to register a variable as an > boot argument with Unikraft that may depend on user input. The patch > provides an implementation for parsing scalar arguments. > > Change since v1: > > Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> > --- > MAINTAINERS.md | 5 + > lib/Config.uk | 1 + > lib/Makefile.uk | 1 + > lib/ukboot/Makefile.uk | 1 + > lib/ukboot/exportsyms.uk | 1 + > lib/ukboot/include/uk/version.h | 6 + > lib/ukboot/version.c | 11 + > lib/uklibparam/Config.uk | 5 + > lib/uklibparam/Makefile.uk | 7 + > lib/uklibparam/exportsyms.uk | 2 + > lib/uklibparam/include/uk/libparam.h | 414 +++++++++++++++++++++ > lib/uklibparam/param.c | 531 +++++++++++++++++++++++++++ > 12 files changed, 985 insertions(+) > create mode 100644 lib/ukboot/include/uk/version.h > create mode 100644 lib/ukboot/version.c > create mode 100644 lib/uklibparam/Config.uk > create mode 100644 lib/uklibparam/Makefile.uk > create mode 100644 lib/uklibparam/exportsyms.uk > create mode 100644 lib/uklibparam/include/uk/libparam.h > create mode 100644 lib/uklibparam/param.c > > diff --git a/MAINTAINERS.md b/MAINTAINERS.md > index e3eb898d..690ca7eb 100644 > --- a/MAINTAINERS.md > +++ b/MAINTAINERS.md > @@ -126,6 +126,11 @@ Try to look for the most precise areas first. In > case nothing fits use > L: minios-devel@xxxxxxxxxxxxx > F: lib/ukdebug/* > > + LIBUKLIBPARAM > + M: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> > + L: minios-devel@xxxxxxxxxxxxx > + F: lib/uklibparam/* > + > UNIKRAFT GENERAL > M: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> > M: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> > diff --git a/lib/Config.uk b/lib/Config.uk > index f61d3b1e..e7b26c8e 100644 > --- a/lib/Config.uk > +++ b/lib/Config.uk > @@ -49,3 +49,4 @@ source "lib/ukswrand/Config.uk" > source "lib/ukbus/Config.uk" > source "lib/uksglist/Config.uk" > source "lib/uknetdev/Config.uk" > +source "lib/uklibparam/Config.uk" > diff --git a/lib/Makefile.uk b/lib/Makefile.uk > index b7ad6287..6f817afc 100644 > --- a/lib/Makefile.uk > +++ b/lib/Makefile.uk > @@ -26,3 +26,4 @@ $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukmpi)) > $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukbus)) > $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uksglist)) > $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uknetdev)) > +$(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uklibparam)) > diff --git a/lib/ukboot/Makefile.uk b/lib/ukboot/Makefile.uk > index 55f205df..ea052019 100644 > --- a/lib/ukboot/Makefile.uk > +++ b/lib/ukboot/Makefile.uk > @@ -4,6 +4,7 @@ CINCLUDES-$(CONFIG_LIBUKBOOT) += > -I$(LIBUKBOOT_BASE)/include > CXXINCLUDES-$(CONFIG_LIBUKBOOT) += -I$(LIBUKBOOT_BASE)/include > > LIBUKBOOT_SRCS-y += $(LIBUKBOOT_BASE)/boot.c > +LIBUKBOOT_SRCS-y += $(LIBUKBOOT_BASE)/version.c The version changes in ukboot library should be in a patch with only those changes and the current patch should only contain uklibparam changes. > > # The main() is in the separate library to fool the LTO. Which is > # trying to resolve the main() function call to whatever is available > diff --git a/lib/ukboot/exportsyms.uk b/lib/ukboot/exportsyms.uk > index 3edc6c6a..4bce9274 100644 > --- a/lib/ukboot/exportsyms.uk > +++ b/lib/ukboot/exportsyms.uk > @@ -1,3 +1,4 @@ > ukplat_entry_argp > ukplat_entry > main > +uk_version This should go in the ukboot version patch. > diff --git a/lib/ukboot/include/uk/version.h > b/lib/ukboot/include/uk/version.h > new file mode 100644 > index 00000000..a1b31c3d > --- /dev/null > +++ b/lib/ukboot/include/uk/version.h > @@ -0,0 +1,6 @@ > +#ifndef _UK_VERSION_H > +#define _UK_VERSION_H > + > +void uk_version(void); > + > +#endif /* _UK_VERSION_H */ This should go in the ukboot version patch. > diff --git a/lib/ukboot/version.c b/lib/ukboot/version.c > new file mode 100644 > index 00000000..559e842d > --- /dev/null > +++ b/lib/ukboot/version.c > @@ -0,0 +1,11 @@ > +#include <uk/version.h> > +#include <uk/essentials.h> > +#include <stdio.h> > + > +void uk_version(void) > +{ > + printf("Unikraft " > + STRINGIFY(UK_CODENAME) " " > + STRINGIFY(UK_FULLVERSION) "\n"); > +} > + This should go in the ukboot version patch. > diff --git a/lib/uklibparam/Config.uk b/lib/uklibparam/Config.uk > new file mode 100644 > index 00000000..18bb43d6 > --- /dev/null > +++ b/lib/uklibparam/Config.uk > @@ -0,0 +1,5 @@ > +config LIBUKLIBPARAM > + bool "uk library parameter: Pass arguments to a unikraft library" > + default n > + select LIBUKDEBUG > + select LIBNOLIBC if !HAVE_LIBC > diff --git a/lib/uklibparam/Makefile.uk b/lib/uklibparam/Makefile.uk > new file mode 100644 > index 00000000..3d450b86 > --- /dev/null > +++ b/lib/uklibparam/Makefile.uk > @@ -0,0 +1,7 @@ > +$(eval $(call addlib_s,libuklibparam,$(CONFIG_LIBUKLIBPARAM))) > + > +ASINCLUDES-y += -I$(LIBUKLIBPARAM_BASE)/include > +CINCLUDES-y += -I$(LIBUKLIBPARAM_BASE)/include > +CXXINCLUDES-y += -I$(LIBUKLIBPARAM_BASE)/include > + > +LIBUKLIBPARAM_SRCS-y += $(LIBUKLIBPARAM_BASE)/param.c > diff --git a/lib/uklibparam/exportsyms.uk b/lib/uklibparam/exportsyms.uk > new file mode 100644 > index 00000000..94b6ca77 > --- /dev/null > +++ b/lib/uklibparam/exportsyms.uk > @@ -0,0 +1,2 @@ > +uk_libparam_parse > +_uk_libparam_lib_add > diff --git a/lib/uklibparam/include/uk/libparam.h > b/lib/uklibparam/include/uk/libparam.h > new file mode 100644 > index 00000000..454cc0d6 > --- /dev/null > +++ b/lib/uklibparam/include/uk/libparam.h > @@ -0,0 +1,414 @@ > +/* SPDX-License-Identifier: BSD-3-Clause */ > +/* > + * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> > + * > + * Copyright (c) 2019, NEC Europe Ltd., NEC Corporation. All rights > reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the > distribution. > + * 3. Neither the name of the copyright holder nor the names of its > + * contributors may be used to endorse or promote products derived > from > + * this software without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > "AS IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER > IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR > OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED > OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + * > + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. > + */ > +#ifndef __UK_LIBPARAM_H > +#define __UK_LIBPARAM_H > + > +#include <uk/config.h> > +#ifndef __ASSEMBLY__ > +#include <uk/ctors.h> > +#include <uk/arch/types.h> > +#include <uk/essentials.h> > +#include <uk/list.h> > +#include <uk/print.h> > + > +#ifdef __cplusplus > +extern C { > +#endif /* __cplusplus */ > +#endif /* !__ASSEMBLY__ */ > + > +/** > + * Variable name prefix/suffix > + */ > +#define UK_LIBPARAM_SECTION uk_lib_arg > +/** > + * Library: section suffix for the name and the > + * parameter. > + */ > +#define LIB_PARAM_SUFFIX __lib_param > +#define LIB_NAME_SUFFIX __lib_str > +/** > + * Library variable names for the name and the > + * parameter. > + */ > +#define LIB_PARAMVAR_PREFIX _lib_param_ > +#define LIB_NAMEVAR_PREFIX _lib_name_ > +/** > + * Parameter within a library: section suffix for the name and the > + * parameter. > + */ > +#define PARAM_SECTION_SUFFIX __param_arg > +#define PARAM_NAME_SUFFIX __param_str > +/** > + * Parameter within a library: variable name prefix for the name and the > + * parameter. > + */ > +#define PARAM_PARAMVAR_PREFIX _param_param_ > +#define PARAM_NAMEVAR_PREFIX _param_name_ > + > +#define __STRINGCONCAT(x, y) x ## y > + > +/** > + * Create a section name. > + * @param libname > + * The library name > + * @param section > + * The section suffix for the library > + */ > +#define _LIB_PARAM_SECTION_NAME(libname, section_name) \ > + __STRINGCONCAT(libname, section_name) > + > +/** > + * Macros to denote the start / stop of a section. > + */ > +#define _SECTION_START(name) __STRINGCONCAT(__start_, name) > +#define _SECTION_STOP(name) __STRINGCONCAT(__stop_, name) > + > +/** > + * Make sure there is a dummy implementation for the UK_PARAM family of > + * functions. > + */ > +#ifndef CONFIG_LIBUKLIBPARAM > +/** > + * Declare a library param. > + * @param name > + * The name of the library param. > + * @param type > + * The type of the param. > + */ > +#define UK_LIB_PARAM(name, type) > + > +#else /* !CONFIG_LIBUKLIBPARAM */ > +/** > + * Each parameter is bit-mapped as follows: > + * --------------------------------------- > + * | sign | copy | size of the parameter | > + * --------------------------------------- > + * 7 6 5 0 > + */ > +/** > + * Sign bit: Shift & Mask > + */ > +#define PARAM_SIGN_SHIFT (7) > +#define PARAM_SIGN_MASK (0x1) > +/** > + * Shallow copy: Shift & Mask > + */ > +#define PARAM_SCOPY_SHIFT (6) > +#define PARAM_SCOPY_MASK (0x1) > +/** > + * Size of the param: Shift & Mask > + */ > +#define PARAM_SIZE_SHIFT (0x0) > +#define PARAM_SIZE_MASK (0x3F) > + > +#ifndef __ASSEMBLY__ > +/** > + * Get the parameter type. > + * @param sign > + * The sign of the data type. > + * @param scopy > + * Flag to indicate shallow copy. > + * 1 - shallow copy. > + * 0 - data copy. > + * @param size > + * The size of the parameter. > + */ > +#define PARAM_TYPE(sign, scopy, size) \ > + ( \ > + ((((__u8) (sign & PARAM_SIGN_MASK)) << \ > + PARAM_SIGN_SHIFT) | \ > + (((__u8) (scopy & PARAM_SCOPY_MASK)) << \ > + PARAM_SCOPY_SHIFT) | \ > + (((__u8) (size & PARAM_SIZE_MASK)) << \ > + PARAM_SIZE_SHIFT)) \ > + ) > + > +/** > + * Support data types as parameters > + */ > +#define _LIB_PARAM___s8 PARAM_TYPE(1, 0, sizeof(__s8)) > +#define _LIB_PARAM_char _LIB_PARAM___s8 > +#define _LIB_PARAM___u8 PARAM_TYPE(0, 0, sizeof(__u8)) > +#define _LIB_PARAM___s16 PARAM_TYPE(1, 0, sizeof(__s16)) > +#define _LIB_PARAM___u16 PARAM_TYPE(0, 0, sizeof(__u16)) > +#define _LIB_PARAM___s32 PARAM_TYPE(1, 0, sizeof(__s32)) > +#define _LIB_PARAM_int _LIB_PARAM___s32 > +#define _LIB_PARAM___u32 PARAM_TYPE(0, 0, sizeof(__u32)) > +#define _LIB_PARAM___s64 PARAM_TYPE(1, 0, sizeof(__s64)) > +#define _LIB_PARAM___u64 PARAM_TYPE(0, 0, sizeof(__u64)) > + > +struct uk_param { > + /* The name of the param */ > + const char *name; > + /* Type information for the param */ > + const __u8 param_type; > + /* Type information for the variable size param */ > + const __u8 param_size; > + /* Define a reference to location of the parameter */ > + __uptr addr; > +}; > + > +struct uk_lib_section { > + /* Library name */ > + const char *lib_name; > + /* Section header of the uk_param args */ > + struct uk_param *sec_addr_start; > + /* Length of the section */ > + __u32 len; > + /* Next section entry */ > + struct uk_list_head next; > +}; > + > +/** > + * Parse through the kernel parameter > + * @param progname > + * The application name > + * @param argc > + * The number of arguments > + * @param argv > + * Reference to the command line arguments > + * @return > + * On success, return the number of argument parsed. > + * On Failure, return the error code. > + */ > +int uk_libparam_parse(const char *progname, int argc, char **argv); > + > +/** > + * Register the library containing kernel parameter. > + * > + * @param lib_sec > + * A reference to the uk_lib_section. > + */ > +void _uk_libparam_lib_add(struct uk_lib_section *lib_sec); > + > +/** > + * Add a variable to a specific section. > + * @param section_name > + * The name of the section. > + * @param align_type > + * The alignment requirements for the variable definitions. > + */ > +#define _LIB_PARAM_SECTION_ADD(section_name, align_type) \ > + __attribute__ ((used, \ > + section( \ > + __STRINGIFY(section_name)), \ > + aligned(sizeof(align_type)) \ > + )) > +/** > + * Create a constructor name. > + * @param libname > + * The library name. > + * @param suffix > + * The suffix appended to the library name. > + */ > +#define _LIB_UK_CONSTRUCT_NAME(libname, suffix) \ > + __STRINGCONCAT(libname, suffix) > + > +/** > + * Create a variable name > + * @param prefix > + * The prefix to the variable name. > + * @param name > + * The name of the variable > + */ > +#define _LIB_VARNAME_SET(prefix, name) \ > + __STRINGCONCAT(prefix, name) > + > +/** > + * Import the section header. > + * @param libname > + * The library name. > + * @param section_suffix > + * The suffix string for the section name > + */ > +#define UK_LIB_IMPORT_SECTION_PARAMS(libname, section_suffix) > \ > + extern char *_SECTION_START( \ > + _LIB_PARAM_SECTION_NAME(libname, \ > + section_suffix)); \ > + extern char *_SECTION_STOP( \ > + _LIB_PARAM_SECTION_NAME(libname, \ > + section_suffix)) \ > + > +/** > + * Create a library name variable and uk_lib_section for each library. > + * @param libname > + * The library name. > + */ > +#define UK_LIB_SECTION_CREATE(section, libname) > \ > + static const char \ > + _LIB_VARNAME_SET(LIB_NAMEVAR_PREFIX, libname)[] = \ > + __STRINGIFY(libname); \ > + static _LIB_PARAM_SECTION_ADD( \ > + _LIB_PARAM_SECTION_NAME(section, \ > + LIB_PARAM_SUFFIX), \ > + void *) \ > + struct uk_lib_section \ > + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname) = \ > + { .lib_name = __NULL, \ > + .sec_addr_start = __NULL, .len = 0 \ > + } > + > +#define UK_LIB_CTOR_PRIO 1 > + > +#define UK_LIB_CONSTRUCTOR_SETUP(prio, name) > \ > + __UK_CTOR_FUNC(prio, name) > + > +/** > + * Create a constructor to initialize the parameters in the library. > + */ > +#define UK_LIB_CONSTRUCTOR_CREATE(libname) > \ > + static void _LIB_UK_CONSTRUCT_NAME(libname, process_arg)(void) \ > + { \ > + int len = (__uptr) &_SECTION_STOP( \ > + _LIB_PARAM_SECTION_NAME( \ > + libname, PARAM_SECTION_SUFFIX) \ > + ) - \ > + (__uptr) &_SECTION_START( \ > + _LIB_PARAM_SECTION_NAME( \ > + libname, PARAM_SECTION_SUFFIX) \ > + ); \ > + if (len > 0) { \ > + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname). \ > + sec_addr_start = \ > + (struct uk_param *) \ > + ALIGN_UP((__uptr) \ > + &_SECTION_START( \ > + _LIB_PARAM_SECTION_NAME(\ > + libname, \ > + PARAM_SECTION_SUFFIX)), \ > + sizeof(void *)); \ > + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname). \ > + len = len; \ > + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname). \ > + lib_name = \ > + &_LIB_VARNAME_SET( \ > + LIB_NAMEVAR_PREFIX, \ > + libname)[0]; \ > + _uk_libparam_lib_add(&_LIB_VARNAME_SET( \ > + LIB_PARAMVAR_PREFIX, \ > + libname) \ > + ); \ > + } \ > + } \ > + > +#define UK_LIB_CONSTRUCTOR_INIT(libname) \ > + UK_LIB_IMPORT_SECTION_PARAMS(libname, \ > + PARAM_SECTION_SUFFIX); \ > + UK_LIB_SECTION_CREATE(UK_LIBPARAM_SECTION, libname); \ > + UK_LIB_CONSTRUCTOR_CREATE(libname) \ > + UK_LIB_CONSTRUCTOR_SETUP(UK_LIB_CTOR_PRIO, \ > + _LIB_UK_CONSTRUCT_NAME(libname, process_arg)) > + > + > +/** > + * Create a constructor to fill in the parameter. > + */ > +#ifdef UK_LIBPARAM_PREFIX > + UK_LIB_CONSTRUCTOR_INIT(UK_LIBPARAM_PREFIX); > +#endif /* UK_LIBPARAM_PREFIX */ > + > +/** > + * Create the fully qualified name of a parameter. > + * > + * @param libname > + * The name of the library > + * @param name > + * The name of the parameter > + */ > +#define _LIB_PARAM_STRING(libname, name) \ > + libname.name > + > +/** > + * Initialize the parameter string in a variable. The name of the > + * parameter is stored in a separate linker section. > + * > + * @param name > + * The name of the variable > + * @param value > + * The string representation of the parameter. > + */ > +#define _LIB_PARAM_NAME_SET(name, value) \ > + static const \ > + char _LIB_VARNAME_SET(PARAM_NAMEVAR_PREFIX, name)[] = \ > + __STRINGIFY(value) > + > + > +/** > + * Initialize the parameter structure. > + * > + * @param param_name > + * The name of the parameter > + * @param type > + * The type of the parameter > + * @param cnt > + * The number of the elements of that type. > + */ > +#define _LIB_UK_PARAM_SET(param_name, type, cnt) \ > + static const \ > + _LIB_PARAM_SECTION_ADD( \ > + _LIB_PARAM_SECTION_NAME( \ > + UK_LIBPARAM_PREFIX, \ > + PARAM_SECTION_SUFFIX), \ > + void * \ > + ) \ > + struct uk_param _LIB_VARNAME_SET(PARAM_SECTION_SUFFIX, \ > + param_name) = { \ > + .name = _LIB_VARNAME_SET(PARAM_NAMEVAR_PREFIX, \ > + param_name), \ > + .param_type = _LIB_PARAM_##type, \ > + .param_size = cnt, \ > + .addr = (__uptr) ¶m_name, \ > + } > + > +/** > + * Declare a library param. > + * @param name > + * The name of the library param. > + * @param type > + * The type of the param. > + */ > +#define UK_LIB_PARAM(name, type) \ > + _LIB_PARAM_NAME_SET(name, _LIB_PARAM_STRING(UK_LIBPARAM_PREFIX, \ > + name)); \ > + _LIB_UK_PARAM_SET(name, type, 1) > +#endif /* !__ASSEMBLY__ */ > +#endif /* CONFIG_LIBUKLIBPARAM */ > + > +#ifndef __ASSEMBLY__ > +#ifdef __cplusplus > +} > +#endif /* __cplusplus */ > +#endif /* !__ASSEMBLY */ > + > +#endif /* __UK_LIBPARAM_H */ > diff --git a/lib/uklibparam/param.c b/lib/uklibparam/param.c > new file mode 100644 > index 00000000..d11acd3f > --- /dev/null > +++ b/lib/uklibparam/param.c > @@ -0,0 +1,531 @@ > +/* SPDX-License-Identifier: BSD-3-Clause */ > +/* > + * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> > + * > + * Copyright (c) 2019, NEC Europe Ltd., NEC Corporation. All rights > reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the > distribution. > + * 3. Neither the name of the copyright holder nor the names of its > + * contributors may be used to endorse or promote products derived > from > + * this software without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > "AS IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER > IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR > OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED > OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + * > + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. > + */ > +#include <string.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <errno.h> > +#include <uk/list.h> > +#include <uk/arch/limits.h> > +#include <uk/print.h> > +#include <uk/assert.h> > +#include <uk/libparam.h> > +#include <uk/version.h> > + > +#define LIB_ARG_SEP "--" > +#define NUMBER_SET(fn, type, value, addr, max, min, errcode, > result_type, fmt)\ > + do { \ > + errno = 0; \ > + result_type result = (result_type)fn(value, NULL, 10); \ > + unsigned long long maxvalue = \ > + (sizeof(type) == sizeof(maxvalue)) ? \ > + (result_type)-1 : \ > + (1ULL << ((sizeof(type) << 3))) - 1; \ > + uk_pr_debug("max value: 0x%llx\n", maxvalue); \ > + if (errno != 0) \ > + errcode = -errno; \ > + else if (result >= maxvalue) { \ > + errcode = 1; \ > + *((type *)addr) = (type)(result & maxvalue); \ > + } else { \ > + errcode = 0; \ > + *((type *)addr) = (type)(result & maxvalue); \ > + } \ > + uk_pr_debug("Converting value %s to %"fmt" %"fmt"\n", \ > + value, *(type *)addr, result); \ > + } while (0) > + > +struct param_args { > + /* Reference to the start of the library */ > + char *lib; > + /* Reference to the start of the parameter */ > + char *param; > + /* Reference to the start of the value */ > + char *value; > + /* length of the library name */ > + __u32 lib_len; > + /* length of the parameter */ > + __u32 param_len; > + /* length of the value */ > + __u32 value_len; > +}; > + > +static UK_LIST_HEAD(uk_libsections); > + > +/** > + * Local functions > + */ > +static int kernel_arg_range_fetch(int argc, char **argv); > +static void uk_usage(const char *progname); > +static int kernel_arg_fetch(char **args, int nr_args, > + struct param_args *pargs, int *rewind); > +static int kernel_lib_fetch(struct param_args *pargs, > + struct uk_lib_section **section); > +static int kernel_parse_arg(struct param_args *pargs, > + struct uk_lib_section *section, > + struct uk_param **param); > +static int kernel_arg_set(void *addr, char *value, int size, int sign); > +static int kernel_args_set(struct param_args *pargs, > + struct uk_param *param); > +static int kernel_value_sanitize(struct param_args *pargs); > + > +void _uk_libparam_lib_add(struct uk_lib_section *lib_sec) > +{ > + uk_pr_info("libname: %s, %d\n", lib_sec->lib_name, lib_sec->len); > + uk_list_add_tail(&lib_sec->next, &uk_libsections); > +} > + > +static void uk_usage(const char *progname) > +{ > + printf("Usage: %s\n", progname); > + printf(" [[UNIKRAFT KERNEL ARGUMENT]].. -- [[APPLICATION > ARGUMENT]]..\n\n"); > + printf("Unikraft library arguments:\n"); > + printf("The library arguments are represented as > [LIBPARAM_PREFIX].[PARAMNAME]\n\n"); > + printf(" -h, --help display this help and exit\n"); > + printf(" -V, --version display Unikraft version and > exit\n"); > +} > + > +static int kernel_arg_range_fetch(int argc, char **argv) > +{ > + int i = 0; > + > + while (i < argc) { > + /* Separate the kernel param from the application parameters */ > + if (strcmp(LIB_ARG_SEP, argv[i]) == 0) > + return i; > + i++; > + } > + > + return -1; > +} > + > +static int kernel_arg_fetch(char **args, int nr_args, > + struct param_args *pargs, int *rewind) > +{ > + int i = 0; > + int rc = 0; > + char *equals_ptr = NULL, *dupl_ptr = NULL; > + int len, cnt = 0, equals = -1; > + > + UK_ASSERT(rewind && pargs); > + > + pargs->param = NULL; > + pargs->value = NULL; > + pargs->param_len = 0; > + pargs->value_len = 0; > + > + for (i = 0; (!pargs->value_len || > + !pargs->param_len) && i < nr_args; i++) { > + uk_pr_debug("at index:%d user args %s\n", i, args[i]); > + len = strlen(args[i]); > + /* if the equals character is present */ > + if (!equals_ptr) > + equals_ptr = strchr(args[i], '='); > + cnt++; > + /* Check for multiple '=' */ > + dupl_ptr = strrchr(args[i], '='); > + if (equals_ptr && dupl_ptr && equals_ptr != dupl_ptr) { > + uk_pr_err("Multiple '=' character found. Skipping > argument %s\n", > + args[i]); > + rc = -EINVAL; > + goto exit; > + } else if (equals < 0) { > + /* Searching for the parameters */ > + if (equals_ptr && (len > 1) && > + (equals_ptr - args[i]) == (len - 1)) { > + /* [libname_prefix].[parameter]= value */ > + uk_pr_debug("Expecting parameter with equals > %s\n", > + args[i]); > + pargs->param = args[i]; > + pargs->param_len = len - 1; > + equals = i; > + } else if (equals_ptr && (len > 1) && > + equals_ptr == args[i]) { > + /* [libname_prefix].[parameter] =value */ > + uk_pr_debug("Expecting equals followed by value > %s\n", > + args[i]); > + pargs->value = equals_ptr + 1; > + pargs->value_len = len - 1; > + equals = i; > + } else if (equals_ptr && len == 1) { > + /* Contains only equals */ > + equals = i; > + continue; > + } else if (equals_ptr) { > + /* [libname_prefix].[parameter]=value */ > + uk_pr_debug("Expecting entire argument %s\n", > + args[i]); > + pargs->param = args[i]; > + pargs->param_len = equals_ptr - args[i]; > + equals = i; > + pargs->value = equals_ptr + 1; > + pargs->value_len = len - (pargs->param_len + 1); > + } else if (!equals_ptr) { > + /* [libname_prefix].[parameter] = value */ > + uk_pr_debug("Expecting parameter alone%s\n", > + args[i]); > + pargs->param = args[i]; > + pargs->param_len = len; > + } else { > + uk_pr_err("Failed to parse the argument %s\n", > + args[i]); > + rc = -EINVAL; > + goto exit; > + } > + } else if (equals >= 0) { > + uk_pr_debug("Expecting value only %s\n", > + args[i]); > + pargs->value = args[i]; > + pargs->value_len = len; > + } else { > + /* Error case */ > + uk_pr_err("Failed to parse the argument:%s\n", args[i]); > + rc = -EINVAL; > + goto exit; > + > + } > + } > + > + uk_pr_debug("pargs->param: %p, pargs->value: %p\n", pargs->param, > + pargs->value); > + if (pargs->param_len != 0 && pargs->value_len == 0) { > + uk_pr_err("Failed to completely parse the user argument\n"); > + rc = -EINVAL; > + goto exit; > + } > + > +exit: > + *rewind = cnt; > + return rc; > +} > + > +/** > + * Kernel Parameter are passed in this format > + * [libname_prefix].[parameter] > + */ > +static int kernel_lib_fetch(struct param_args *pargs, > + struct uk_lib_section **section) > +{ > + char *libparam; > + struct uk_lib_section *iter; > + > + UK_ASSERT(section && pargs); > + pargs->lib_len = 0; > + libparam = memchr(pargs->param, '.', pargs->param_len); > + if (!libparam) { > + uk_pr_err("Failed to identify the library\n"); > + goto error_exit; > + } > + > + uk_list_for_each_entry(iter, &uk_libsections, next) { > + uk_pr_debug("Lib: %s, libname: %s %ld\n", iter->lib_name, > + pargs->param, libparam - pargs->param); > + /** > + * Compare the length of the library names to avoid having > + * library with a similar prefix wrongly matching. > + */ > + if ((strlen(iter->lib_name) == > + (size_t) (libparam - pargs->param)) && > + memcmp(pargs->param, iter->lib_name, > + (libparam - pargs->param)) == 0) { > + *section = iter; > + pargs->lib_len = libparam - pargs->param; > + return 0; > + } > + } > + uk_pr_err("Failed to fetch the library\n"); > + > +error_exit: > + *section = NULL; > + pargs->lib_len = 0; > + return -EINVAL; > +} > + > +static int kernel_parse_arg(struct param_args *pargs, > + struct uk_lib_section *section, > + struct uk_param **param) > +{ > + int i = 0; > + struct uk_param *iter; > + int len = 0; > + > + UK_ASSERT(section && param && pargs); > + > + len = section->len / sizeof(struct uk_param); > + iter = section->sec_addr_start; > + uk_pr_debug("Section length %d section@%p, uk_param: %lu\n", len, iter, > + sizeof(*iter)); > + > + for (i = 0; i < len; i++, iter++) { > + UK_ASSERT(iter->name); > + uk_pr_debug("Param name: %s at address: %p\n", iter->name, > + iter); > + /** > + * Compare the length of the library names to avoid having > + * library with a similar prefix wrongly matching. > + */ > + if ((strlen(iter->name) == pargs->param_len) && > + memcmp(iter->name, pargs->param, pargs->param_len) == 0) { > + *param = iter; > + return 0; > + } > + } > + > + uk_pr_err("Failed to identify the parameter\n"); > + *param = NULL; > + return -EINVAL; > +} > + > +static int kernel_arg_set(void *addr, char *value, int size, int sign) > +{ > + int error = 0; > + > + /** > + * Check for the output address instead of UK_ASSERT because this is > + * a user provided input. > + */ > + if (!addr) { > + uk_pr_err("Invalid output buffer\n"); > + goto error_exit; > + } > + > + switch (size) { > + case 1: > + if (sign) { > + *((__s8 *)addr) = *value; > + if (strnlen(value, 2) > 1) > + error = 1; > + } else > + NUMBER_SET(strtoul, __u8, value, addr, __U8_MAX, > + __U8_MIN, error, __u32, __PRIu8); > + break; > + case 2: > + if (sign) > + NUMBER_SET(strtol, __s16, value, addr, __S16_MAX, > + __S16_MIN, error, __u32, __PRIs16); > + else > + NUMBER_SET(strtoul, __u16, value, addr, __U16_MAX, > + __U16_MIN, error, __u32, __PRIu16); > + break; > + case 4: > + if (sign) > + NUMBER_SET(strtol, __s32, value, addr, __S32_MAX, > + __S32_MIN, error, __u32, __PRIs32); > + else > + NUMBER_SET(strtoul, __u32, value, addr, __U32_MAX, > + __U32_MIN, error, __u32, __PRIu32); > + break; > + case 8: > + if (sign) > + NUMBER_SET(strtoll, __s64, value, addr, __S64_MAX, > + __S64_MIN, error, __u64, __PRIs64); > + else > + NUMBER_SET(strtoull, __u64, value, addr, __U64_MAX, > + __U64_MIN, error, __u64, __PRIu64); > + break; > + default: > + uk_pr_err("Cannot understand type of size %d\n", size); > + goto error_exit; > + } > + if (error < 0) > + goto error_exit; > + else if (error == 1) > + uk_pr_warn("Overflow/Underflow detected in value %s\n", value); > + return 0; > + > +error_exit: > + uk_pr_err("Failed to convert value %s\n", value); > + return -EINVAL; > +} > + > +static int kernel_args_set(struct param_args *pargs, > + struct uk_param *param) > +{ > + int rc = 0; > + int sign = (param->param_type >> PARAM_SIGN_SHIFT) & PARAM_SIGN_MASK; > + int scopy = (param->param_type >> PARAM_SCOPY_SHIFT) & PARAM_SCOPY_MASK; > + int param_type = (param->param_type >> PARAM_SIZE_SHIFT) > + & PARAM_SIZE_MASK; > + uk_pr_debug("Parameter value %s, type: %d, sign: %d scopy: %d\n", > + pargs->value, param_type, sign, scopy); > + > + if (scopy == 1) > + /* Reference the pointer instead of copying the value */ > + *((__uptr *)param->addr) = (__uptr) pargs->value; > + else { > + if (param->param_size == 1) { > + rc = kernel_arg_set((void *)param->addr, > + pargs->value, param_type, sign); > + } else { > + uk_pr_err("Error: Cannot find the parameter\n"); > + rc = -EINVAL; > + } > + } > + > + return rc; > +} > + > +/** > + * The function removes parse for quotes around the value. > + * TODO: We do not support nested '"'. > + */ > +static int kernel_value_sanitize(struct param_args *pargs) > +{ > + int rc = 0; > + char *ptr; > + char *start_idx = NULL; > + char *end_idx = NULL; > + int qcnt = 0; > + > + UK_ASSERT(pargs && pargs->value); > + ptr = pargs->value; > + uk_pr_debug("Sanitizing value %s (length %d)\n", pargs->value, > + pargs->value_len); > + > + do { > + switch (*ptr) { > + case ' ': > + case '\r': > + case '\n': > + case '\t': > + case '\v': > + ptr++; > + break; > + case'\'': > + case '"': > + if (start_idx) > + end_idx = ptr; > + else if (!start_idx) > + start_idx = ptr + 1; > + ptr++; > + qcnt++; > + break; > + default: > + if (!start_idx) > + start_idx = ptr; > + ptr++; > + break; > + } > + } while (*ptr != '\0' && !(end_idx && start_idx)); > + if (!end_idx) > + end_idx = ptr; > + > + uk_pr_debug("Adjusting start to %p & end to %p #quotes: %d\n", > + start_idx, end_idx, qcnt); > + > + if (qcnt == 1) { > + uk_pr_err("Value %s not quoted properly\n", pargs->value); > + rc = -EINVAL; > + } else if (start_idx && end_idx) { > + memset(pargs->value, '\0', start_idx - pargs->value); > + memset(end_idx, '\0', > + (pargs->value + pargs->value_len) - end_idx); > + pargs->value = start_idx; > + pargs->value_len = end_idx - start_idx; > + } > + uk_pr_debug("Sanitized value %s (length %d)\n", pargs->value, > + pargs->value_len); > + > + return rc; > +} > + > +int uk_libparam_parse(const char *progname, int argc, char **argv) > +{ > + int keindex = 0; > + int rc = 0, cnt = 0, args_read; > + struct param_args pargs = {0}; > + struct uk_lib_section *section = NULL; > + struct uk_param *param = NULL; > + > + keindex = kernel_arg_range_fetch(argc, argv); > + if (keindex < 0) { > + uk_pr_info("No library arguments found\n"); > + return 0; > + } > + > + uk_pr_debug("Library argument ends at %d\n", keindex); > + > + while (cnt < keindex) { > + /* help and version */ > + if (strcmp(argv[cnt], "-h") == 0 || > + strcmp(argv[cnt], "--help") == 0) { > + uk_usage(progname); > + ukplat_halt(); > + } else if (strcmp(argv[cnt], "-V") == 0 || > + strcmp(argv[cnt], "--version") == 0) { > + uk_version(); > + ukplat_halt(); > + } > + > + args_read = 0; > + /* Fetch the argument from the input */ > + rc = kernel_arg_fetch(&argv[cnt], (keindex - cnt), > + &pargs, &args_read); > + if (rc < 0) { > + uk_pr_err("Failed to fetch arg between index %d and > %d\n", > + cnt, (cnt + args_read)); > > Just to make this a bit more user friendly, it would be good to print out the > actual argument, not just the index. This would be particularly useful when > providing a large list of args. > > > + cnt += args_read; > + continue; > + } > + uk_pr_debug("Processing argument %s\n", pargs.param); > + cnt += args_read; > + > + /* Fetch library for the argument */ > + rc = kernel_lib_fetch(&pargs, §ion); > + if (rc < 0 || !section) { > + uk_pr_err("Failed to identify the library\n"); > + continue; > + } > + > + /* Fetch the parameter for the argument */ > + rc = kernel_parse_arg(&pargs, section, ¶m); > + if (rc < 0 || !param) { > + uk_pr_err("Failed to parse arg\n"); > + continue; > + } > + > + rc = kernel_value_sanitize(&pargs); > + if (rc < 0) { > + uk_pr_err("Failed to sanitize %s param\n", pargs.param); > + continue; > + } > + > + rc = kernel_args_set(&pargs, param); > + uk_pr_info("Parsed %d args\n", cnt); > + } > + > + /* Replacing the -- with progname */ > + argv[keindex] = DECONST(char *, progname); > + > + return keindex + 1; > +} > -- > 2.20.1 > > > _______________________________________________ > Minios-devel mailing list > Minios-devel@xxxxxxxxxxxxxxxxxxxx > https://lists.xenproject.org/mailman/listinfo/minios-devel > > _______________________________________________ > Minios-devel mailing list > Minios-devel@xxxxxxxxxxxxxxxxxxxx > https://lists.xenproject.org/mailman/listinfo/minios-devel > _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |