From 8a1169b515470b959633c5fba69a135d7789a96f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 14 Sep 2014 14:10:23 -0600 Subject: In kernel mode, we have to duplicate the callers argv[] buffer when exec'ing new tasks. When the argv[] buffer is needed, the caller's address environment will not longer be in place --- nuttx/binfmt/binfmt_exec.c | 102 ++++++++++++++++++++++++++++++++++-- nuttx/binfmt/binfmt_execmodule.c | 15 +++--- nuttx/binfmt/binfmt_internal.h | 39 ++++++++++++-- nuttx/binfmt/binfmt_unloadmodule.c | 31 +++++++++++ nuttx/include/nuttx/binfmt/binfmt.h | 5 ++ 5 files changed, 178 insertions(+), 14 deletions(-) diff --git a/nuttx/binfmt/binfmt_exec.c b/nuttx/binfmt/binfmt_exec.c index 63bac45d2..a250b2269 100644 --- a/nuttx/binfmt/binfmt_exec.c +++ b/nuttx/binfmt/binfmt_exec.c @@ -58,6 +58,89 @@ * Private Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: binfmt_copyargv + * + * Description: + * In the kernel build, the argv list will likely lie in the caller's + * address environment and, hence, by inaccessible when we swith to the + * address environment of the new process address environment. So we + * do not have any real option other than to copy the callers argv[] list. + * + * Input Parameter: + * bin - Load structure + * argv - Argument list + * + * Returned Value: + * Zero (OK) on sucess; a negater erro value on failure. + * + ****************************************************************************/ + +static inline int binfmt_copyargv(FAR struct binary_s *bin, FAR char * const *argv) +{ +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) + FAR char *ptr; + size_t argsize; + int i; + + /* Get the size of the argument list */ + + bin->argbuffer = (FAR char *)NULL; + i = 0; + + if (argv) + { + argsize = 0; + for (i = 0; i < CONFIG_MAX_TASK_ARGS && argv[i]; i++) + { + argsize += (strlen(argv[i]) + 1); + } + + bvdbg("args=%d argsize=%lu\n", i, (unsigned long)argsize); + + /* Allocate a temporary argument buffer */ + + i = 0; + + if (argsize > 0) + { + bin->argbuffer = (FAR char *)kmm_malloc(argsize); + if (!bin->argbuffer) + { + bdbg("ERROR: Failed to allocate the argument buffer\n"); + return -ENOMEM; + } + + /* Copy the argv list */ + + ptr = bin->argbuffer; + for (; i < CONFIG_MAX_TASK_ARGS && argv[i]; i++) + { + bin->argv[i] = ptr; + argsize = strlen(argv[i]) + 1; + memcpy(ptr, argv[i], argsize); + ptr += argsize; + } + } + } + + /* Nullify the remainder of the list */ + + for (; i <= CONFIG_MAX_TASK_ARGS; i++) + { + bin->argv[i] = NULL; + } + + return OK; + +#else + /* Just save the caller's argv pointer */ + + bin->argv = argv; + return OK; +#endif +} + /**************************************************************************** * Private Data ****************************************************************************/ @@ -115,19 +198,30 @@ int exec(FAR const char *filename, FAR char * const *argv, goto errout; } - /* Load the module into memory */ + /* Initialize the binary structure */ bin->filename = filename; - bin->argv = argv; bin->exports = exports; bin->nexports = nexports; + /* Copy the argv[] list */ + + ret = binfmt_copyargv(bin, argv); + if (ret < 0) + { + err = -ret; + bdbg("ERROR: Failed to copy argv[]: %d\n", err); + goto errout_with_bin; + } + + /* Load the module into memory */ + ret = load_module(bin); if (ret < 0) { err = get_errno(); bdbg("ERROR: Failed to load program '%s': %d\n", filename, err); - goto errout_with_bin; + goto errout_with_argv; } /* Disable pre-emption so that the executed module does @@ -164,6 +258,8 @@ int exec(FAR const char *filename, FAR char * const *argv, errout_with_lock: sched_unlock(); unload_module(bin); +errout_with_argv: + binfmt_freeargv(bin); errout_with_bin: kmm_free(bin); errout: diff --git a/nuttx/binfmt/binfmt_execmodule.c b/nuttx/binfmt/binfmt_execmodule.c index dae892571..f2ff5db7a 100644 --- a/nuttx/binfmt/binfmt_execmodule.c +++ b/nuttx/binfmt/binfmt_execmodule.c @@ -192,7 +192,7 @@ int exec_module(FAR const struct binary_s *binp) if (!stack) { err = ENOMEM; - goto errout_with_kstack; + goto errout_with_addrenv; } /* Initialize the task */ @@ -203,9 +203,13 @@ int exec_module(FAR const struct binary_s *binp) { err = get_errno(); bdbg("task_init() failed: %d\n", err); - goto errout_with_kstack; + goto errout_with_addrenv; } + /* We can free the argument buffer now */ + + binfmt_freeargv(binp); + /* Note that tcb->flags are not modified. 0=normal task */ /* tcb->flags |= TCB_FLAG_TTYPE_TASK; */ @@ -217,7 +221,7 @@ int exec_module(FAR const struct binary_s *binp) { bdbg("ERROR: up_addrenv_select() failed: %d\n", ret); err = -ret; - goto errout_with_addrenv; + goto errout_with_tcbinit; } #endif @@ -292,12 +296,7 @@ errout_with_tcbinit: kumm_free(stack); goto errout; -errout_with_kstack: -#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) - (void)up_addrenv_kstackfree(tcb); - errout_with_addrenv: -#endif #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) (void)up_addrenv_restore(&oldenv); diff --git a/nuttx/binfmt/binfmt_internal.h b/nuttx/binfmt/binfmt_internal.h index fa750543a..184263183 100644 --- a/nuttx/binfmt/binfmt_internal.h +++ b/nuttx/binfmt/binfmt_internal.h @@ -55,7 +55,8 @@ #undef EXTERN #if defined(__cplusplus) #define EXTERN extern "C" -extern "C" { +extern "C" +{ #else #define EXTERN extern #endif @@ -71,14 +72,46 @@ EXTERN FAR struct binfmt_s *g_binfmts; * Public Function Prototypes ***********************************************************************/ -/* Dump the contents of struct binary_s */ +/**************************************************************************** + * Name: dump_module + * + * Description: + * Dump the contents of struct binary_s. + * + * Input Parameter: + * bin - Load structure + * + * Returned Value: + * Zero (OK) on success; a negater errno value on failure + * + ****************************************************************************/ #if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_BINFMT) -EXTERN int dump_module(FAR const struct binary_s *bin); +int dump_module(FAR const struct binary_s *bin); #else # define dump_module(bin) #endif +/**************************************************************************** + * Name: binfmt_freeargv + * + * Description: + * Release the copied argv[] list. + * + * Input Parameter: + * bin - Load structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) +void binfmt_freeargv(FAR struct binary_s *bin); +#else +# define binfmt_freeargv(bin) +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/nuttx/binfmt/binfmt_unloadmodule.c b/nuttx/binfmt/binfmt_unloadmodule.c index 67b957b20..ce1b0e53d 100644 --- a/nuttx/binfmt/binfmt_unloadmodule.c +++ b/nuttx/binfmt/binfmt_unloadmodule.c @@ -179,6 +179,10 @@ int unload_module(FAR struct binary_s *binp) } #endif + /* Free any allocated argv[] strings */ + + binfmt_freeargv(binp); + /* Unmap mapped address spaces */ if (binp->mapped) @@ -207,5 +211,32 @@ int unload_module(FAR struct binary_s *binp) return OK; } +/**************************************************************************** + * Name: binfmt_freeargv + * + * Description: + * Release the copied argv[] list. + * + * Input Parameter: + * binp - Load structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) +void binfmt_freeargv(FAR struct binary_s *binp) +{ + if (binp->argbuffer) + { + /* Free the argument buffer */ + + kmm_free(binp->argbuffer); + binp->argbuffer = NULL; + } +} +#endif + #endif /* CONFIG_BINFMT_DISABLE */ diff --git a/nuttx/include/nuttx/binfmt/binfmt.h b/nuttx/include/nuttx/binfmt/binfmt.h index fbc50b3c7..56ee57445 100644 --- a/nuttx/include/nuttx/binfmt/binfmt.h +++ b/nuttx/include/nuttx/binfmt/binfmt.h @@ -97,7 +97,12 @@ struct binary_s /* Information provided to the loader to load and bind a module */ FAR const char *filename; /* Full path to the binary to be loaded (See NOTE 1 above) */ +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) + FAR char *argbuffer; /* Allocated argument list */ + FAR char *argv[CONFIG_MAX_TASK_ARGS+1]; /* Copy of argument list */ +#else FAR char * const *argv; /* Argument list */ +#endif FAR const struct symtab_s *exports; /* Table of exported symbols */ int nexports; /* The number of symbols in exports[] */ -- cgit v1.2.3