mirror of https://github.com/xemu-project/xemu.git
linux-user/syscall: Extract do_execve() from do_syscall1()
execve() is a particular case of execveat(). In order to add do_execveat(), first factor do_execve() out. Signed-off-by: Drew DeVault <sir@cmpwn.com> Message-Id: <20221104081015.706009-1-sir@cmpwn.com> [PMD: Split of bigger patch, filled description, fixed style] Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20221104173632.1052-5-philmd@linaro.org> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
parent
5667a1aebe
commit
156e1f6718
|
@ -8357,6 +8357,119 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
|
|||
return safe_openat(dirfd, path(pathname), flags, mode);
|
||||
}
|
||||
|
||||
static int do_execve(CPUArchState *cpu_env,
|
||||
abi_long pathname, abi_long guest_argp,
|
||||
abi_long guest_envp)
|
||||
{
|
||||
int ret;
|
||||
char **argp, **envp;
|
||||
int argc, envc;
|
||||
abi_ulong gp;
|
||||
abi_ulong addr;
|
||||
char **q;
|
||||
void *p;
|
||||
|
||||
argc = 0;
|
||||
|
||||
for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
argc++;
|
||||
}
|
||||
envc = 0;
|
||||
for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
envc++;
|
||||
}
|
||||
|
||||
argp = g_new0(char *, argc + 1);
|
||||
envp = g_new0(char *, envc + 1);
|
||||
|
||||
for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
goto execve_efault;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
*q = lock_user_string(addr);
|
||||
if (!*q) {
|
||||
goto execve_efault;
|
||||
}
|
||||
}
|
||||
*q = NULL;
|
||||
|
||||
for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
goto execve_efault;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
*q = lock_user_string(addr);
|
||||
if (!*q) {
|
||||
goto execve_efault;
|
||||
}
|
||||
}
|
||||
*q = NULL;
|
||||
|
||||
/*
|
||||
* Although execve() is not an interruptible syscall it is
|
||||
* a special case where we must use the safe_syscall wrapper:
|
||||
* if we allow a signal to happen before we make the host
|
||||
* syscall then we will 'lose' it, because at the point of
|
||||
* execve the process leaves QEMU's control. So we use the
|
||||
* safe syscall wrapper to ensure that we either take the
|
||||
* signal as a guest signal, or else it does not happen
|
||||
* before the execve completes and makes it the other
|
||||
* program's problem.
|
||||
*/
|
||||
p = lock_user_string(pathname);
|
||||
if (!p) {
|
||||
goto execve_efault;
|
||||
}
|
||||
|
||||
if (is_proc_myself(p, "exe")) {
|
||||
ret = get_errno(safe_execve(exec_path, argp, envp));
|
||||
} else {
|
||||
ret = get_errno(safe_execve(p, argp, envp));
|
||||
}
|
||||
|
||||
unlock_user(p, pathname, 0);
|
||||
|
||||
goto execve_end;
|
||||
|
||||
execve_efault:
|
||||
ret = -TARGET_EFAULT;
|
||||
|
||||
execve_end:
|
||||
for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp) || !addr) {
|
||||
break;
|
||||
}
|
||||
unlock_user(*q, addr, 0);
|
||||
}
|
||||
for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp) || !addr) {
|
||||
break;
|
||||
}
|
||||
unlock_user(*q, addr, 0);
|
||||
}
|
||||
|
||||
g_free(argp);
|
||||
g_free(envp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define TIMER_MAGIC 0x0caf0000
|
||||
#define TIMER_MAGIC_MASK 0xffff0000
|
||||
|
||||
|
@ -8867,103 +8980,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||
return ret;
|
||||
#endif
|
||||
case TARGET_NR_execve:
|
||||
{
|
||||
char **argp, **envp;
|
||||
int argc, envc;
|
||||
abi_ulong gp;
|
||||
abi_ulong guest_argp;
|
||||
abi_ulong guest_envp;
|
||||
abi_ulong addr;
|
||||
char **q;
|
||||
|
||||
argc = 0;
|
||||
guest_argp = arg2;
|
||||
for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
|
||||
if (get_user_ual(addr, gp))
|
||||
return -TARGET_EFAULT;
|
||||
if (!addr)
|
||||
break;
|
||||
argc++;
|
||||
}
|
||||
envc = 0;
|
||||
guest_envp = arg3;
|
||||
for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
|
||||
if (get_user_ual(addr, gp))
|
||||
return -TARGET_EFAULT;
|
||||
if (!addr)
|
||||
break;
|
||||
envc++;
|
||||
}
|
||||
|
||||
argp = g_new0(char *, argc + 1);
|
||||
envp = g_new0(char *, envc + 1);
|
||||
|
||||
for (gp = guest_argp, q = argp; gp;
|
||||
gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp))
|
||||
goto execve_efault;
|
||||
if (!addr)
|
||||
break;
|
||||
if (!(*q = lock_user_string(addr)))
|
||||
goto execve_efault;
|
||||
}
|
||||
*q = NULL;
|
||||
|
||||
for (gp = guest_envp, q = envp; gp;
|
||||
gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp))
|
||||
goto execve_efault;
|
||||
if (!addr)
|
||||
break;
|
||||
if (!(*q = lock_user_string(addr)))
|
||||
goto execve_efault;
|
||||
}
|
||||
*q = NULL;
|
||||
|
||||
if (!(p = lock_user_string(arg1)))
|
||||
goto execve_efault;
|
||||
/* Although execve() is not an interruptible syscall it is
|
||||
* a special case where we must use the safe_syscall wrapper:
|
||||
* if we allow a signal to happen before we make the host
|
||||
* syscall then we will 'lose' it, because at the point of
|
||||
* execve the process leaves QEMU's control. So we use the
|
||||
* safe syscall wrapper to ensure that we either take the
|
||||
* signal as a guest signal, or else it does not happen
|
||||
* before the execve completes and makes it the other
|
||||
* program's problem.
|
||||
*/
|
||||
if (is_proc_myself(p, "exe")) {
|
||||
ret = get_errno(safe_execve(exec_path, argp, envp));
|
||||
} else {
|
||||
ret = get_errno(safe_execve(p, argp, envp));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
goto execve_end;
|
||||
|
||||
execve_efault:
|
||||
ret = -TARGET_EFAULT;
|
||||
|
||||
execve_end:
|
||||
for (gp = guest_argp, q = argp; *q;
|
||||
gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp)
|
||||
|| !addr)
|
||||
break;
|
||||
unlock_user(*q, addr, 0);
|
||||
}
|
||||
for (gp = guest_envp, q = envp; *q;
|
||||
gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp)
|
||||
|| !addr)
|
||||
break;
|
||||
unlock_user(*q, addr, 0);
|
||||
}
|
||||
|
||||
g_free(argp);
|
||||
g_free(envp);
|
||||
}
|
||||
return ret;
|
||||
return do_execve(cpu_env, arg1, arg2, arg3);
|
||||
case TARGET_NR_chdir:
|
||||
if (!(p = lock_user_string(arg1)))
|
||||
return -TARGET_EFAULT;
|
||||
|
|
Loading…
Reference in New Issue