Skip to content

Commit 7e69872

Browse files
committed
update buildkit patches to 7.0
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
1 parent 33434b9 commit 7e69872

7 files changed

+538
-1
lines changed

docker-bake.hcl

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ target "buildkit" {
5454
inherits = ["mainline"]
5555
args = {
5656
BINARY_PREFIX = "buildkit-"
57-
QEMU_PATCHES = "cpu-max,buildkit-direct-execve-v6.2"
57+
QEMU_PATCHES = "cpu-max,buildkit-direct-execve-v7.0"
5858
QEMU_PRESERVE_ARGV0 = ""
5959
}
6060
cache-from = ["${REPO}:buildkit-master"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
From 4d6248d103cf749ab5a624903929d5d31754e09a Mon Sep 17 00:00:00 2001
2+
From: Tibor Vass <tibor@docker.com>
3+
Date: Mon, 1 Jun 2020 23:08:25 +0000
4+
Subject: [PATCH] linux-user: have execve call qemu via /proc/self/exe to not
5+
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 <tibor@docker.com>
20+
---
21+
linux-user/syscall.c | 35 ++++++++++++++++++++++++++++++-----
22+
1 file changed, 30 insertions(+), 5 deletions(-)
23+
24+
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
25+
index f65045efe6..73054926a0 100644
26+
--- a/linux-user/syscall.c
27+
+++ b/linux-user/syscall.c
28+
@@ -8776,10 +8776,37 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
29+
envc++;
30+
}
31+
32+
- argp = g_new0(char *, argc + 1);
33+
+ argp = g_new0(char *, argc + 4);
34+
envp = g_new0(char *, envc + 1);
35+
36+
- for (gp = guest_argp, q = argp; gp;
37+
+ if (!(p = lock_user_string(arg1)))
38+
+ goto execve_efault;
39+
+
40+
+ /* if pathname is /proc/self/exe then retrieve the path passed to qemu via command line */
41+
+ if (is_proc_myself(p, "exe")) {
42+
+ CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
43+
+ TaskState *ts = cpu->opaque;
44+
+ p = ts->bprm->filename;
45+
+ }
46+
+
47+
+ /* retrieve guest argv0 */
48+
+ if (get_user_ual(addr, guest_argp))
49+
+ goto execve_efault;
50+
+
51+
+ /*
52+
+ * From the guest, the call
53+
+ * execve(pathname, [argv0, argv1], envp)
54+
+ * on the host, becomes:
55+
+ * execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp)
56+
+ * where qemu_progname is the error message prefix for qemu
57+
+ */
58+
+ argp[0] = (char*)error_get_progname();
59+
+ argp[1] = (char*)"-0";
60+
+ argp[2] = (char*)lock_user_string(addr);
61+
+ argp[3] = p;
62+
+
63+
+ /* copy guest argv1 onwards to host argv4 onwards */
64+
+ for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp;
65+
gp += sizeof(abi_ulong), q++) {
66+
if (get_user_ual(addr, gp))
67+
goto execve_efault;
68+
@@ -8801,8 +8828,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
69+
}
70+
*q = NULL;
71+
72+
- if (!(p = lock_user_string(arg1)))
73+
- goto execve_efault;
74+
/* Although execve() is not an interruptible syscall it is
75+
* a special case where we must use the safe_syscall wrapper:
76+
* if we allow a signal to happen before we make the host
77+
@@ -8813,7 +8838,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
78+
* before the execve completes and makes it the other
79+
* program's problem.
80+
*/
81+
- ret = get_errno(safe_execve(p, argp, envp));
82+
+ ret = get_errno(safe_execve("/proc/self/exe", argp, envp));
83+
unlock_user(p, arg1, 0);
84+
85+
goto execve_end;
86+
--
87+
2.34.0
88+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
From d83023eb7a0574cad224c7d88ac8dcf9d745afa3 Mon Sep 17 00:00:00 2001
2+
From: Tibor Vass <tibor@docker.com>
3+
Date: Tue, 2 Jun 2020 10:39:48 +0000
4+
Subject: [PATCH] linux-user: lookup user program in PATH
5+
6+
Signed-off-by: Tibor Vass <tibor@docker.com>
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 fbc9bcfd5f..30f163de81 100644
13+
--- a/linux-user/main.c
14+
+++ b/linux-user/main.c
15+
@@ -558,6 +558,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+
@@ -623,7 +662,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.34.0
76+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
From 1f69e640ec9a5a9f8b7ab9101f4807808f59bc1d Mon Sep 17 00:00:00 2001
2+
From: Tibor Vass <tibor@docker.com>
3+
Date: Sat, 27 Jun 2020 21:42:51 +0000
4+
Subject: [PATCH] linux-user: path in execve should be relative to working dir
5+
6+
Fixes regression introduced in parent commit where PATH handling was introduced.
7+
8+
When guest calls execve(filename, argp, envp) filename can be relative in which
9+
case Linux makes it relative to the working directory.
10+
11+
However, since execve is now handled by exec-ing qemu process again, filename
12+
would first get looked up in PATH in main() before calling host's execve.
13+
14+
With this change, if filename is relative and exists in working directory as
15+
well as in PATH, working directory will get precedence over PATH if guest is
16+
doing an execve syscall, but not if relative filename comes from qemu's argv.
17+
18+
Signed-off-by: Tibor Vass <tibor@docker.com>
19+
---
20+
include/qemu/path.h | 1 +
21+
linux-user/syscall.c | 9 +++++++--
22+
util/path.c | 30 ++++++++++++++++++++++++++++++
23+
3 files changed, 38 insertions(+), 2 deletions(-)
24+
25+
diff --git a/include/qemu/path.h b/include/qemu/path.h
26+
index c6292a9709..a81fb51e1f 100644
27+
--- a/include/qemu/path.h
28+
+++ b/include/qemu/path.h
29+
@@ -3,5 +3,6 @@
30+
31+
void init_paths(const char *prefix);
32+
const char *path(const char *pathname);
33+
+const char *prepend_workdir_if_relative(const char *path);
34+
35+
#endif
36+
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
37+
index 73054926a0..b92be0963e 100644
38+
--- a/linux-user/syscall.c
39+
+++ b/linux-user/syscall.c
40+
@@ -8798,12 +8798,17 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
41+
* execve(pathname, [argv0, argv1], envp)
42+
* on the host, becomes:
43+
* execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp)
44+
- * where qemu_progname is the error message prefix for qemu
45+
+ * where qemu_progname is the error message prefix for qemu.
46+
+ * Note: if pathname is relative, it will be prepended with the current working directory.
47+
*/
48+
argp[0] = (char*)error_get_progname();
49+
argp[1] = (char*)"-0";
50+
argp[2] = (char*)lock_user_string(addr);
51+
- argp[3] = p;
52+
+ argp[3] = (char*)prepend_workdir_if_relative(p);
53+
+ if (!argp[3]) {
54+
+ ret = -host_to_target_errno(errno);
55+
+ goto execve_end;
56+
+ }
57+
58+
/* copy guest argv1 onwards to host argv4 onwards */
59+
for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp;
60+
diff --git a/util/path.c b/util/path.c
61+
index 8e174eb436..f7907b8238 100644
62+
--- a/util/path.c
63+
+++ b/util/path.c
64+
@@ -68,3 +68,33 @@ const char *path(const char *name)
65+
qemu_mutex_unlock(&lock);
66+
return ret;
67+
}
68+
+
69+
+/* Prepends working directory if path is relative.
70+
+ * If path is absolute, it is returned as-is without any allocation.
71+
+ * Otherwise, caller is responsible to free returned path.
72+
+ * Returns NULL and sets errno upon error.
73+
+ * Note: realpath is not called to let the kernel do the rest of the resolution.
74+
+ */
75+
+const char *prepend_workdir_if_relative(const char *path)
76+
+{
77+
+ char buf[PATH_MAX];
78+
+ char *p;
79+
+ int i, j, k;
80+
+
81+
+ if (!path || path[0] == '/') return path;
82+
+
83+
+ if (!getcwd(buf, PATH_MAX)) return NULL;
84+
+ i = strlen(buf);
85+
+ j = strlen(path);
86+
+ k = i + 1 + j + 1; /* workdir + '/' + path + '\0' */
87+
+ if (i + j > PATH_MAX) {
88+
+ errno = ERANGE;
89+
+ return NULL;
90+
+ }
91+
+ if (!(p = malloc(k * sizeof(char*)))) return NULL;
92+
+
93+
+ if (!strncat(p, buf, i)) return NULL;
94+
+ if (!strncat(p, "/", 1)) return NULL;
95+
+ if (!strncat(p, path, j)) return NULL;
96+
+ return p;
97+
+}
98+
--
99+
2.34.0
100+

0 commit comments

Comments
 (0)