mirror of
https://github.com/apache/nuttx.git
synced 2026-06-07 01:05:54 +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:
@@ -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