aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPierrick Bouvier <pierrick.bouvier@linaro.org>2023-07-05 14:10:23 +0200
committerMichael Tokarev <mjt@tls.msk.ru>2023-07-31 08:52:38 +0300
commit7b336dcd06d727c2ec98ec5dcf95f38c83ac4b9f (patch)
tree90e1ca5f428e880c2666a41d9fb2b84487e2b5af /linux-user
parentc280ac3b60da2dbda06ca3fd1bd1937ae8396ae0 (diff)
linux-user/syscall: Implement execve without execveat
Support for execveat syscall was implemented in 55bbe4 and is available since QEMU 8.0.0. It relies on host execveat, which is widely available on most of Linux kernels today. However, this change breaks qemu-user self emulation, if "host" qemu version is less than 8.0.0. Indeed, it does not implement yet execveat. This strange use case happens with most of distribution today having binfmt support. With a concrete failing example: $ qemu-x86_64-7.2 qemu-x86_64-8.0 /bin/bash -c /bin/ls /bin/bash: line 1: /bin/ls: Function not implemented -> not implemented means execve returned ENOSYS qemu-user-static 7.2 and 8.0 can be conveniently grabbed from debian packages qemu-user-static* [1]. One usage of this is running wine-arm64 from linux-x64 (details [2]). This is by updating qemu embedded in docker image that we ran into this issue. The solution to update host qemu is not always possible. Either it's complicated or ask you to recompile it, or simply is not accessible (GitLab CI, GitHub Actions). Thus, it could be worth to implement execve without relying on execveat, which is the goal of this patch. This patch was tested with example presented in this commit message. [1] http://ftp.us.debian.org/debian/pool/main/q/qemu/ [1] https://www.linaro.org/blog/emulate-windows-on-arm/ Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Michael Tokarev <mjt@tls.msk.ru> Message-Id: <20230705121023.973284-1-pierrick.bouvier@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> (cherry picked from commit 7a8d9f3a0e882df50681e40f09c29cfb4966ea2d) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/syscall.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index cf24331f4a..71559f81d4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -659,6 +659,7 @@ safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
#endif
safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
int, options, struct rusage *, rusage)
+safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
safe_syscall5(int, execveat, int, dirfd, const char *, filename,
char **, argv, char **, envp, int, flags)
#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
@@ -8402,9 +8403,9 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
return safe_openat(dirfd, path(pathname), flags, mode);
}
-static int do_execveat(CPUArchState *cpu_env, int dirfd,
- abi_long pathname, abi_long guest_argp,
- abi_long guest_envp, int flags)
+static int do_execv(CPUArchState *cpu_env, int dirfd,
+ abi_long pathname, abi_long guest_argp,
+ abi_long guest_envp, int flags, bool is_execveat)
{
int ret;
char **argp, **envp;
@@ -8483,11 +8484,14 @@ static int do_execveat(CPUArchState *cpu_env, int dirfd,
goto execve_efault;
}
+ const char *exe = p;
if (is_proc_myself(p, "exe")) {
- ret = get_errno(safe_execveat(dirfd, exec_path, argp, envp, flags));
- } else {
- ret = get_errno(safe_execveat(dirfd, p, argp, envp, flags));
+ exe = exec_path;
}
+ ret = is_execveat
+ ? safe_execveat(dirfd, exe, argp, envp, flags)
+ : safe_execve(exe, argp, envp);
+ ret = get_errno(ret);
unlock_user(p, pathname, 0);
@@ -9026,9 +9030,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return ret;
#endif
case TARGET_NR_execveat:
- return do_execveat(cpu_env, arg1, arg2, arg3, arg4, arg5);
+ return do_execv(cpu_env, arg1, arg2, arg3, arg4, arg5, true);
case TARGET_NR_execve:
- return do_execveat(cpu_env, AT_FDCWD, arg1, arg2, arg3, 0);
+ return do_execv(cpu_env, AT_FDCWD, arg1, arg2, arg3, 0, false);
case TARGET_NR_chdir:
if (!(p = lock_user_string(arg1)))
return -TARGET_EFAULT;