mirror of
https://github.com/qemu/qemu.git
synced 2025-08-14 03:15:54 +00:00
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);
|
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 0x0caf0000
|
||||||
#define TIMER_MAGIC_MASK 0xffff0000
|
#define TIMER_MAGIC_MASK 0xffff0000
|
||||||
|
|
||||||
@ -8867,103 +8980,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
case TARGET_NR_execve:
|
case TARGET_NR_execve:
|
||||||
{
|
return do_execve(cpu_env, arg1, arg2, arg3);
|
||||||
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;
|
|
||||||
case TARGET_NR_chdir:
|
case TARGET_NR_chdir:
|
||||||
if (!(p = lock_user_string(arg1)))
|
if (!(p = lock_user_string(arg1)))
|
||||||
return -TARGET_EFAULT;
|
return -TARGET_EFAULT;
|
||||||
|
Loading…
Reference in New Issue
Block a user