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:
Ville Juven
2022-04-04 13:11:06 +03:00
committed by Xiang Xiao
parent 6b1ee4c2e2
commit 4c1b66246d
17 changed files with 133 additions and 46 deletions
+22 -4
View File
@@ -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: