mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:58:59 +08:00
env_dup: Fix copying of env between address environments
If address environments are in use, it is not possible to simply memcpy from from one process to another. The current implementation of env_dup does precisely this and thus, it fails at once when it is attempted between two user processes. The solution is to use the kernel's heap as an intermediate buffer. This is a simple, effective and common way to do a fork(). Obviously this is not needed for kernel processes.
This commit is contained in:
@@ -117,6 +117,50 @@ void binfmt_freeargv(FAR char * const *argv);
|
||||
# define binfmt_freeargv(argv)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: binfmt_copyenv
|
||||
*
|
||||
* Description:
|
||||
* In the kernel build, the environment exists in the parent's address
|
||||
* environment and, hence, will be inaccessible when we switch to the
|
||||
* address environment of the new process. So we do not have any real
|
||||
* option other than to copy the parents envp list into an intermediate
|
||||
* buffer that resides in neutral kernel memory.
|
||||
*
|
||||
* Input Parameters:
|
||||
* envp - Allocated environment strings
|
||||
*
|
||||
* Returned Value:
|
||||
* A non-zero copy is returned on success.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_DISABLE_ENVIRON
|
||||
# define binfmt_copyenv(envp) binfmt_copyargv(envp)
|
||||
#else
|
||||
# define binfmt_copyenv(envp) (envp)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: binfmt_freeenv
|
||||
*
|
||||
* Description:
|
||||
* Release the copied envp[] list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* envp - Allocated environment strings
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_DISABLE_ENVIRON
|
||||
# define binfmt_freeenv(envp) binfmt_freeargv(envp)
|
||||
#else
|
||||
# define binfmt_freeenv(envp)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: builtin_initialize
|
||||
*
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
* program.
|
||||
* argv - A pointer to an array of string arguments. The end of the
|
||||
* array is indicated with a NULL entry.
|
||||
* envp - A pointer to an array of environment strings. Terminated with
|
||||
* a NULL entry.
|
||||
* exports - The address of the start of the caller-provided symbol
|
||||
* table. This symbol table contains the addresses of symbols
|
||||
* exported by the caller and made available for linking the
|
||||
@@ -69,8 +71,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
int exec_spawn(FAR const char *filename, FAR char * const *argv,
|
||||
FAR const struct symtab_s *exports, int nexports,
|
||||
FAR const posix_spawnattr_t *attr)
|
||||
FAR char * const *envp, FAR const struct symtab_s *exports,
|
||||
int nexports, FAR const posix_spawnattr_t *attr)
|
||||
{
|
||||
FAR struct binary_s *bin;
|
||||
int pid;
|
||||
@@ -121,7 +123,7 @@ int exec_spawn(FAR const char *filename, FAR char * const *argv,
|
||||
|
||||
/* Then start the module */
|
||||
|
||||
pid = exec_module(bin, filename, argv);
|
||||
pid = exec_module(bin, filename, argv, envp);
|
||||
if (pid < 0)
|
||||
{
|
||||
ret = pid;
|
||||
@@ -228,7 +230,7 @@ int exec(FAR const char *filename, FAR char * const *argv,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = exec_spawn(filename, argv, exports, nexports, NULL);
|
||||
ret = exec_spawn(filename, argv, NULL, exports, nexports, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(-ret);
|
||||
|
||||
@@ -112,7 +112,8 @@ static void exec_ctors(FAR void *arg)
|
||||
****************************************************************************/
|
||||
|
||||
int exec_module(FAR const struct binary_s *binp,
|
||||
FAR const char *filename, FAR char * const *argv)
|
||||
FAR const char *filename, FAR char * const *argv,
|
||||
FAR char * const *envp)
|
||||
{
|
||||
FAR struct task_tcb_s *tcb;
|
||||
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
|
||||
@@ -150,6 +151,18 @@ int exec_module(FAR const struct binary_s *binp,
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a copy of the environment here */
|
||||
|
||||
if (envp)
|
||||
{
|
||||
envp = binfmt_copyenv(envp);
|
||||
if (!envp)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_args;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
|
||||
/* Instantiate the address environment containing the user heap */
|
||||
|
||||
@@ -157,7 +170,7 @@ int exec_module(FAR const struct binary_s *binp,
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: up_addrenv_select() failed: %d\n", ret);
|
||||
goto errout_with_args;
|
||||
goto errout_with_envp;
|
||||
}
|
||||
|
||||
binfo("Initialize the user heap (heapsize=%d)\n", binp->addrenv.heapsize);
|
||||
@@ -173,12 +186,12 @@ int exec_module(FAR const struct binary_s *binp,
|
||||
if (argv && argv[0])
|
||||
{
|
||||
ret = nxtask_init(tcb, argv[0], binp->priority, NULL,
|
||||
binp->stacksize, binp->entrypt, &argv[1]);
|
||||
binp->stacksize, binp->entrypt, &argv[1], envp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = nxtask_init(tcb, filename, binp->priority, NULL,
|
||||
binp->stacksize, binp->entrypt, argv);
|
||||
binp->stacksize, binp->entrypt, argv, envp);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
@@ -187,7 +200,10 @@ int exec_module(FAR const struct binary_s *binp,
|
||||
goto errout_with_addrenv;
|
||||
}
|
||||
|
||||
/* The copied argv and envp can now be released */
|
||||
|
||||
binfmt_freeargv(argv);
|
||||
binfmt_freeenv(envp);
|
||||
|
||||
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)
|
||||
/* Allocate the kernel stack */
|
||||
@@ -281,7 +297,9 @@ errout_with_tcbinit:
|
||||
errout_with_addrenv:
|
||||
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
|
||||
up_addrenv_restore(&oldenv);
|
||||
errout_with_envp:
|
||||
#endif
|
||||
binfmt_freeenv(envp);
|
||||
errout_with_args:
|
||||
binfmt_freeargv(argv);
|
||||
errout_with_tcb:
|
||||
|
||||
Reference in New Issue
Block a user