Skip to content

Commit 8bf932d

Browse files
authored
Merge pull request #265 from crazy-max/qemu10
update qemu to 10.0.4
2 parents 39df745 + b2bfc44 commit 8bf932d

12 files changed

+754
-36
lines changed

Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# syntax=docker/dockerfile:1
22

33
ARG GO_VERSION=1.23
4-
ARG ALPINE_VERSION=3.21
5-
ARG XX_VERSION=1.6.1
4+
ARG ALPINE_VERSION=3.22
5+
ARG XX_VERSION=1.7.0
66

77
ARG QEMU_VERSION=HEAD
88
ARG QEMU_REPO=https://github.com/qemu/qemu
@@ -62,13 +62,13 @@ RUN <<eof
6262
eof
6363

6464
FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS base
65-
RUN apk add --no-cache git clang lld python3 llvm make ninja pkgconfig glib-dev gcc musl-dev perl bash
65+
RUN apk add --no-cache git clang lld python3 llvm make ninja pkgconfig glib-dev gcc musl-dev pcre2-dev perl bash
6666
COPY --from=xx / /
6767
ENV PATH=/qemu/install-scripts:$PATH
6868
WORKDIR /qemu
6969

7070
ARG TARGETPLATFORM
71-
RUN xx-apk add --no-cache musl-dev gcc glib-dev glib-static linux-headers zlib-static
71+
RUN xx-apk add --no-cache musl-dev gcc glib-dev glib-static linux-headers pcre2-dev pcre2-static zlib-static
7272
RUN set -e; \
7373
[ "$(xx-info arch)" = "ppc64le" ] && XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple; \
7474
[ "$(xx-info arch)" = "386" ] && XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple; \

docker-bake.hcl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ variable "QEMU_REPO" {
55
default = "https://github.com/qemu/qemu"
66
}
77
variable "QEMU_VERSION" {
8-
default = "v9.2.2"
8+
default = "v10.0.4"
99
}
1010
variable "QEMU_PATCHES" {
1111
default = "cpu-max-arm"
@@ -59,7 +59,7 @@ target "buildkit" {
5959
inherits = ["mainline"]
6060
args = {
6161
BINARY_PREFIX = "buildkit-"
62-
QEMU_PATCHES = "${QEMU_PATCHES},buildkit-direct-execve-v9.2"
62+
QEMU_PATCHES = "${QEMU_PATCHES},buildkit-direct-execve-v10.0"
6363
QEMU_PRESERVE_ARGV0 = ""
6464
}
6565
cache-from = ["${REPO}:buildkit-master"]

patches/aports.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
10.0.4,c9b4dbf9a02f4616c7e82fd4b97938da0f058c03
12
9.2.2,334b162677f79271980f61d410dc136b98b93fc4
23
8.1.50,e9d411e67e815ab0fcf1d00885cb55dd0f99e810
34
8.0.50,6225632b267a3d2bf6700a8fce41df60a68c187b
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
From b0ccc59b95c5520847354bd4ab57694e7510a4ea Mon Sep 17 00:00:00 2001
2+
From: CrazyMax <[email protected]>
3+
Date: Fri, 8 Sep 2023 10:47:29 +0200
4+
Subject: [PATCH 1/7] linux-user: have execve call qemu via /proc/self/exe to
5+
not rely on binfmt_misc
6+
7+
It is assumed that when a guest program calls execve syscall it wants to
8+
execute a program on the same guest architecture and not the host architecture.
9+
10+
Previously, such a guest program would have execve syscall error out with:
11+
"exec format error".
12+
13+
A common solution is to register the qemu binary in binfmt_misc but that is not a
14+
userland-friendly solution, requiring to modify kernel state.
15+
16+
This patch injects /proc/self/exe as the first parameter and the qemu program name
17+
as argv[0] to execve.
18+
19+
Signed-off-by: Tibor Vass <[email protected]>
20+
Signed-off-by: CrazyMax <[email protected]>
21+
---
22+
linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++-------------
23+
1 file changed, 31 insertions(+), 13 deletions(-)
24+
25+
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
26+
index 2edbd1ef15..b9808851e0 100644
27+
--- a/linux-user/syscall.c
28+
+++ b/linux-user/syscall.c
29+
@@ -8489,10 +8489,37 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
30+
envc++;
31+
}
32+
33+
- argp = g_new0(char *, argc + 1);
34+
+ argp = g_new0(char *, argc + 4);
35+
envp = g_new0(char *, envc + 1);
36+
37+
- for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
38+
+ if (!(p = lock_user_string(pathname)))
39+
+ goto execve_efault;
40+
+
41+
+ /* if pathname is /proc/self/exe then retrieve the path passed to qemu via command line */
42+
+ if (is_proc_myself(p, "exe")) {
43+
+ CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
44+
+ TaskState *ts = cpu->opaque;
45+
+ p = ts->bprm->filename;
46+
+ }
47+
+
48+
+ /* retrieve guest argv0 */
49+
+ if (get_user_ual(addr, guest_argp))
50+
+ goto execve_efault;
51+
+
52+
+ /*
53+
+ * From the guest, the call
54+
+ * execve(pathname, [argv0, argv1], envp)
55+
+ * on the host, becomes:
56+
+ * execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp)
57+
+ * where qemu_progname is the error message prefix for qemu
58+
+ */
59+
+ argp[0] = (char*)error_get_progname();
60+
+ argp[1] = (char*)"-0";
61+
+ argp[2] = (char*)lock_user_string(addr);
62+
+ argp[3] = p;
63+
+
64+
+ /* copy guest argv1 onwards to host argv4 onwards */
65+
+ for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp; gp += sizeof(abi_ulong), q++) {
66+
if (get_user_ual(addr, gp)) {
67+
goto execve_efault;
68+
}
69+
@@ -8531,18 +8558,9 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
70+
* before the execve completes and makes it the other
71+
* program's problem.
72+
*/
73+
- p = lock_user_string(pathname);
74+
- if (!p) {
75+
- goto execve_efault;
76+
- }
77+
-
78+
- const char *exe = p;
79+
- if (is_proc_myself(p, "exe")) {
80+
- exe = exec_path;
81+
- }
82+
ret = is_execveat
83+
- ? safe_execveat(dirfd, exe, argp, envp, flags)
84+
- : safe_execve(exe, argp, envp);
85+
+ ? safe_execveat(dirfd, "/proc/self/exe", argp, envp, flags)
86+
+ : safe_execve("/proc/self/exe", argp, envp);
87+
ret = get_errno(ret);
88+
89+
unlock_user(p, pathname, 0);
90+
--
91+
2.39.3 (Apple Git-146)
92+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
From 4a12f3c8b2d145ccbd5a437fbdf03e84f7b43b49 Mon Sep 17 00:00:00 2001
2+
From: Tibor Vass <[email protected]>
3+
Date: Tue, 2 Jun 2020 10:39:48 +0000
4+
Subject: [PATCH 2/7] linux-user: lookup user program in PATH
5+
6+
Signed-off-by: Tibor Vass <[email protected]>
7+
---
8+
linux-user/main.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
9+
1 file changed, 44 insertions(+), 1 deletion(-)
10+
11+
diff --git a/linux-user/main.c b/linux-user/main.c
12+
index 149e35432e..dd70ee10f1 100644
13+
--- a/linux-user/main.c
14+
+++ b/linux-user/main.c
15+
@@ -600,6 +600,45 @@ static void usage(int exitcode)
16+
exit(exitcode);
17+
}
18+
19+
+/*
20+
+ * path_lookup searches for an executable filename in the directories named by the PATH environment variable.
21+
+ * Returns a copy of filename if it is an absolute path or could not find a match.
22+
+ * Caller is responsible to free returned string.
23+
+ * Adapted from musl's execvp implementation.
24+
+ */
25+
+static char *path_lookup(char *filename) {
26+
+ const char *p, *z, *path = getenv("PATH");
27+
+ size_t l, k;
28+
+ struct stat buf;
29+
+
30+
+ /* if PATH is not set or filename is absolute path return filename */
31+
+ if (!path || !filename || filename[0] == '/')
32+
+ return strndup(filename, NAME_MAX+1);
33+
+
34+
+ k = strnlen(filename, NAME_MAX+1);
35+
+ if (k > NAME_MAX) {
36+
+ errno = ENAMETOOLONG;
37+
+ return NULL;
38+
+ }
39+
+ l = strnlen(path, PATH_MAX-1)+1;
40+
+
41+
+ for (p = path; ; p = z) {
42+
+ char *b = calloc(l+k+1, sizeof(char));
43+
+ z = strchrnul(p, ':');
44+
+ if (z-p >= l) {
45+
+ if (!*z++) break;
46+
+ continue;
47+
+ }
48+
+ memcpy(b, p, z-p);
49+
+ b[z-p] = '/';
50+
+ memcpy(b+(z-p)+(z>p), filename, k+1);
51+
+ if (!stat(b, &buf) && !(buf.st_mode & S_IFDIR) && (buf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
52+
+ return b;
53+
+ if (!*z++) break;
54+
+ }
55+
+ return strndup(filename, NAME_MAX+1);
56+
+}
57+
+
58+
static int parse_args(int argc, char **argv)
59+
{
60+
const char *r;
61+
@@ -665,7 +704,11 @@ static int parse_args(int argc, char **argv)
62+
exit(EXIT_FAILURE);
63+
}
64+
65+
- exec_path = argv[optind];
66+
+ /* not freeing exec_path as it is needed for the lifetime of the process */
67+
+ if (!(exec_path = path_lookup(argv[optind]))) {
68+
+ (void) fprintf(stderr, "qemu: could not find user program %s: %s\n", exec_path, strerror(errno));
69+
+ exit(EXIT_FAILURE);
70+
+ }
71+
72+
return optind;
73+
}
74+
--
75+
2.39.3 (Apple Git-146)
76+
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
From 0927d01f4f35c8ed3d8639d811fbd2ca49831fa4 Mon Sep 17 00:00:00 2001
2+
From: CrazyMax <[email protected]>
3+
Date: Wed, 3 May 2023 20:54:37 +0200
4+
Subject: [PATCH 3/7] linux-user: path in execve should be relative to working
5+
dir
6+
7+
Fixes regression introduced in parent commit where PATH handling was introduced.
8+
9+
When guest calls execve(filename, argp, envp) filename can be relative in which
10+
case Linux makes it relative to the working directory.
11+
12+
However, since execve is now handled by exec-ing qemu process again, filename
13+
would first get looked up in PATH in main() before calling host's execve.
14+
15+
With this change, if filename is relative and exists in working directory as
16+
well as in PATH, working directory will get precedence over PATH if guest is
17+
doing an execve syscall, but not if relative filename comes from qemu's argv.
18+
19+
Signed-off-by: Tibor Vass <[email protected]>
20+
Signed-off-by: CrazyMax <[email protected]>
21+
---
22+
include/qemu/path.h | 1 +
23+
linux-user/syscall.c | 9 +++++++--
24+
util/path.c | 32 ++++++++++++++++++++++++++++++++
25+
3 files changed, 40 insertions(+), 2 deletions(-)
26+
27+
diff --git a/include/qemu/path.h b/include/qemu/path.h
28+
index c6292a9709..a81fb51e1f 100644
29+
--- a/include/qemu/path.h
30+
+++ b/include/qemu/path.h
31+
@@ -3,5 +3,6 @@
32+
33+
void init_paths(const char *prefix);
34+
const char *path(const char *pathname);
35+
+const char *prepend_workdir_if_relative(const char *path);
36+
37+
#endif
38+
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
39+
index b9808851e0..c6de1303ae 100644
40+
--- a/linux-user/syscall.c
41+
+++ b/linux-user/syscall.c
42+
@@ -8511,12 +8511,17 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
43+
* execve(pathname, [argv0, argv1], envp)
44+
* on the host, becomes:
45+
* execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp)
46+
- * where qemu_progname is the error message prefix for qemu
47+
+ * where qemu_progname is the error message prefix for qemu.
48+
+ * Note: if pathname is relative, it will be prepended with the current working directory.
49+
*/
50+
argp[0] = (char*)error_get_progname();
51+
argp[1] = (char*)"-0";
52+
argp[2] = (char*)lock_user_string(addr);
53+
- argp[3] = p;
54+
+ argp[3] = (char*)prepend_workdir_if_relative(p);
55+
+ if (!argp[3]) {
56+
+ ret = -host_to_target_errno(errno);
57+
+ goto execve_end;
58+
+ }
59+
60+
/* copy guest argv1 onwards to host argv4 onwards */
61+
for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp; gp += sizeof(abi_ulong), q++) {
62+
diff --git a/util/path.c b/util/path.c
63+
index 8e174eb436..06fe2663b8 100644
64+
--- a/util/path.c
65+
+++ b/util/path.c
66+
@@ -68,3 +68,35 @@ const char *path(const char *name)
67+
qemu_mutex_unlock(&lock);
68+
return ret;
69+
}
70+
+
71+
+/* Prepends working directory if path is relative.
72+
+ * If path is absolute, it is returned as-is without any allocation.
73+
+ * Otherwise, caller is responsible to free returned path.
74+
+ * Returns NULL and sets errno upon error.
75+
+ * Note: realpath is not called to let the kernel do the rest of the resolution.
76+
+ */
77+
+const char *prepend_workdir_if_relative(const char *path)
78+
+{
79+
+ char buf[PATH_MAX];
80+
+ char *p;
81+
+ int i, j, k;
82+
+
83+
+ if (!path || path[0] == '/') return path;
84+
+
85+
+ if (!getcwd(buf, PATH_MAX)) return NULL;
86+
+ i = strlen(buf);
87+
+ j = strlen(path);
88+
+ k = i + 1 + j + 1; /* workdir + '/' + path + '\0' */
89+
+ if (i + j > PATH_MAX) {
90+
+ errno = ERANGE;
91+
+ return NULL;
92+
+ }
93+
+ if (!(p = malloc(k * sizeof(char*)))) return NULL;
94+
+
95+
+ p[0] = '\0';
96+
+
97+
+ if (!strncat(p, buf, i)) return NULL;
98+
+ if (!strncat(p, "/", 1)) return NULL;
99+
+ if (!strncat(p, path, j)) return NULL;
100+
+ return p;
101+
+}
102+
--
103+
2.39.3 (Apple Git-146)
104+

0 commit comments

Comments
 (0)