diff --git a/docker-bake.hcl b/docker-bake.hcl index f5da15a8..7670b65f 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -5,7 +5,7 @@ variable "QEMU_REPO" { default = "https://github.com/qemu/qemu" } variable "QEMU_VERSION" { - default = "v8.1.5" + default = "v9.0.2" } variable "QEMU_PATCHES" { default = "cpu-max-arm" @@ -59,7 +59,7 @@ target "buildkit" { inherits = ["mainline"] args = { BINARY_PREFIX = "buildkit-" - QEMU_PATCHES = "${QEMU_PATCHES},buildkit-direct-execve-v8.1" + QEMU_PATCHES = "${QEMU_PATCHES},buildkit-direct-execve-v9.0" QEMU_PRESERVE_ARGV0 = "" } cache-from = ["${REPO}:buildkit-master"] @@ -80,7 +80,7 @@ target "buildkit-test" { target "desktop" { inherits = ["mainline"] args = { - QEMU_PATCHES = "${QEMU_PATCHES},subreaper-prctl,pretcode" + QEMU_PATCHES = "${QEMU_PATCHES},pretcode" } cache-from = ["${REPO}:desktop-master"] } diff --git a/patches/aports.config b/patches/aports.config index 020eb2cc..342cd214 100644 --- a/patches/aports.config +++ b/patches/aports.config @@ -1,3 +1,4 @@ +9.0.20,a88afee3b85341cc34096e8144cd3ca316fe936a 8.1.50,e9d411e67e815ab0fcf1d00885cb55dd0f99e810 8.0.50,6225632b267a3d2bf6700a8fce41df60a68c187b 7.2.50,ed7a3122a32f53094f51e55abe68d416910e01ad diff --git a/patches/buildkit-direct-execve-v9.0/0001-linux-user-have-execve-call-qemu-via-proc-self-exe-t.patch b/patches/buildkit-direct-execve-v9.0/0001-linux-user-have-execve-call-qemu-via-proc-self-exe-t.patch new file mode 100644 index 00000000..eb320a90 --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0001-linux-user-have-execve-call-qemu-via-proc-self-exe-t.patch @@ -0,0 +1,92 @@ +From b0ccc59b95c5520847354bd4ab57694e7510a4ea Mon Sep 17 00:00:00 2001 +From: CrazyMax +Date: Fri, 8 Sep 2023 10:47:29 +0200 +Subject: [PATCH 1/7] linux-user: have execve call qemu via /proc/self/exe to + not rely on binfmt_misc + +It is assumed that when a guest program calls execve syscall it wants to +execute a program on the same guest architecture and not the host architecture. + +Previously, such a guest program would have execve syscall error out with: +"exec format error". + +A common solution is to register the qemu binary in binfmt_misc but that is not a +userland-friendly solution, requiring to modify kernel state. + +This patch injects /proc/self/exe as the first parameter and the qemu program name +as argv[0] to execve. + +Signed-off-by: Tibor Vass +Signed-off-by: CrazyMax +--- + linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++------------- + 1 file changed, 31 insertions(+), 13 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 2edbd1ef15..b9808851e0 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -8489,10 +8489,37 @@ static int do_execv(CPUArchState *cpu_env, int dirfd, + envc++; + } + +- argp = g_new0(char *, argc + 1); ++ argp = g_new0(char *, argc + 4); + envp = g_new0(char *, envc + 1); + +- for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { ++ if (!(p = lock_user_string(pathname))) ++ goto execve_efault; ++ ++ /* if pathname is /proc/self/exe then retrieve the path passed to qemu via command line */ ++ if (is_proc_myself(p, "exe")) { ++ CPUState *cpu = env_cpu((CPUArchState *)cpu_env); ++ TaskState *ts = cpu->opaque; ++ p = ts->bprm->filename; ++ } ++ ++ /* retrieve guest argv0 */ ++ if (get_user_ual(addr, guest_argp)) ++ goto execve_efault; ++ ++ /* ++ * From the guest, the call ++ * execve(pathname, [argv0, argv1], envp) ++ * on the host, becomes: ++ * execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp) ++ * where qemu_progname is the error message prefix for qemu ++ */ ++ argp[0] = (char*)error_get_progname(); ++ argp[1] = (char*)"-0"; ++ argp[2] = (char*)lock_user_string(addr); ++ argp[3] = p; ++ ++ /* copy guest argv1 onwards to host argv4 onwards */ ++ for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + goto execve_efault; + } +@@ -8531,18 +8558,9 @@ static int do_execv(CPUArchState *cpu_env, int dirfd, + * before the execve completes and makes it the other + * program's problem. + */ +- p = lock_user_string(pathname); +- if (!p) { +- goto execve_efault; +- } +- +- const char *exe = p; +- if (is_proc_myself(p, "exe")) { +- exe = exec_path; +- } + ret = is_execveat +- ? safe_execveat(dirfd, exe, argp, envp, flags) +- : safe_execve(exe, argp, envp); ++ ? safe_execveat(dirfd, "/proc/self/exe", argp, envp, flags) ++ : safe_execve("/proc/self/exe", argp, envp); + ret = get_errno(ret); + + unlock_user(p, pathname, 0); +-- +2.39.3 (Apple Git-146) + diff --git a/patches/buildkit-direct-execve-v9.0/0002-linux-user-lookup-user-program-in-PATH.patch b/patches/buildkit-direct-execve-v9.0/0002-linux-user-lookup-user-program-in-PATH.patch new file mode 100644 index 00000000..86a9a92d --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0002-linux-user-lookup-user-program-in-PATH.patch @@ -0,0 +1,76 @@ +From 4a12f3c8b2d145ccbd5a437fbdf03e84f7b43b49 Mon Sep 17 00:00:00 2001 +From: Tibor Vass +Date: Tue, 2 Jun 2020 10:39:48 +0000 +Subject: [PATCH 2/7] linux-user: lookup user program in PATH + +Signed-off-by: Tibor Vass +--- + linux-user/main.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 44 insertions(+), 1 deletion(-) + +diff --git a/linux-user/main.c b/linux-user/main.c +index 149e35432e..dd70ee10f1 100644 +--- a/linux-user/main.c ++++ b/linux-user/main.c +@@ -600,6 +600,45 @@ static void usage(int exitcode) + exit(exitcode); + } + ++/* ++ * path_lookup searches for an executable filename in the directories named by the PATH environment variable. ++ * Returns a copy of filename if it is an absolute path or could not find a match. ++ * Caller is responsible to free returned string. ++ * Adapted from musl's execvp implementation. ++ */ ++static char *path_lookup(char *filename) { ++ const char *p, *z, *path = getenv("PATH"); ++ size_t l, k; ++ struct stat buf; ++ ++ /* if PATH is not set or filename is absolute path return filename */ ++ if (!path || !filename || filename[0] == '/') ++ return strndup(filename, NAME_MAX+1); ++ ++ k = strnlen(filename, NAME_MAX+1); ++ if (k > NAME_MAX) { ++ errno = ENAMETOOLONG; ++ return NULL; ++ } ++ l = strnlen(path, PATH_MAX-1)+1; ++ ++ for (p = path; ; p = z) { ++ char *b = calloc(l+k+1, sizeof(char)); ++ z = strchrnul(p, ':'); ++ if (z-p >= l) { ++ if (!*z++) break; ++ continue; ++ } ++ memcpy(b, p, z-p); ++ b[z-p] = '/'; ++ memcpy(b+(z-p)+(z>p), filename, k+1); ++ if (!stat(b, &buf) && !(buf.st_mode & S_IFDIR) && (buf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) ++ return b; ++ if (!*z++) break; ++ } ++ return strndup(filename, NAME_MAX+1); ++} ++ + static int parse_args(int argc, char **argv) + { + const char *r; +@@ -665,7 +704,11 @@ static int parse_args(int argc, char **argv) + exit(EXIT_FAILURE); + } + +- exec_path = argv[optind]; ++ /* not freeing exec_path as it is needed for the lifetime of the process */ ++ if (!(exec_path = path_lookup(argv[optind]))) { ++ (void) fprintf(stderr, "qemu: could not find user program %s: %s\n", exec_path, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } + + return optind; + } +-- +2.39.3 (Apple Git-146) + diff --git a/patches/buildkit-direct-execve-v9.0/0003-linux-user-path-in-execve-should-be-relative-to-work.patch b/patches/buildkit-direct-execve-v9.0/0003-linux-user-path-in-execve-should-be-relative-to-work.patch new file mode 100644 index 00000000..54441932 --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0003-linux-user-path-in-execve-should-be-relative-to-work.patch @@ -0,0 +1,104 @@ +From 0927d01f4f35c8ed3d8639d811fbd2ca49831fa4 Mon Sep 17 00:00:00 2001 +From: CrazyMax +Date: Wed, 3 May 2023 20:54:37 +0200 +Subject: [PATCH 3/7] linux-user: path in execve should be relative to working + dir + +Fixes regression introduced in parent commit where PATH handling was introduced. + +When guest calls execve(filename, argp, envp) filename can be relative in which +case Linux makes it relative to the working directory. + +However, since execve is now handled by exec-ing qemu process again, filename +would first get looked up in PATH in main() before calling host's execve. + +With this change, if filename is relative and exists in working directory as +well as in PATH, working directory will get precedence over PATH if guest is +doing an execve syscall, but not if relative filename comes from qemu's argv. + +Signed-off-by: Tibor Vass +Signed-off-by: CrazyMax +--- + include/qemu/path.h | 1 + + linux-user/syscall.c | 9 +++++++-- + util/path.c | 32 ++++++++++++++++++++++++++++++++ + 3 files changed, 40 insertions(+), 2 deletions(-) + +diff --git a/include/qemu/path.h b/include/qemu/path.h +index c6292a9709..a81fb51e1f 100644 +--- a/include/qemu/path.h ++++ b/include/qemu/path.h +@@ -3,5 +3,6 @@ + + void init_paths(const char *prefix); + const char *path(const char *pathname); ++const char *prepend_workdir_if_relative(const char *path); + + #endif +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index b9808851e0..c6de1303ae 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -8511,12 +8511,17 @@ static int do_execv(CPUArchState *cpu_env, int dirfd, + * execve(pathname, [argv0, argv1], envp) + * on the host, becomes: + * execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp) +- * where qemu_progname is the error message prefix for qemu ++ * where qemu_progname is the error message prefix for qemu. ++ * Note: if pathname is relative, it will be prepended with the current working directory. + */ + argp[0] = (char*)error_get_progname(); + argp[1] = (char*)"-0"; + argp[2] = (char*)lock_user_string(addr); +- argp[3] = p; ++ argp[3] = (char*)prepend_workdir_if_relative(p); ++ if (!argp[3]) { ++ ret = -host_to_target_errno(errno); ++ goto execve_end; ++ } + + /* copy guest argv1 onwards to host argv4 onwards */ + for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp; gp += sizeof(abi_ulong), q++) { +diff --git a/util/path.c b/util/path.c +index 8e174eb436..06fe2663b8 100644 +--- a/util/path.c ++++ b/util/path.c +@@ -68,3 +68,35 @@ const char *path(const char *name) + qemu_mutex_unlock(&lock); + return ret; + } ++ ++/* Prepends working directory if path is relative. ++ * If path is absolute, it is returned as-is without any allocation. ++ * Otherwise, caller is responsible to free returned path. ++ * Returns NULL and sets errno upon error. ++ * Note: realpath is not called to let the kernel do the rest of the resolution. ++ */ ++const char *prepend_workdir_if_relative(const char *path) ++{ ++ char buf[PATH_MAX]; ++ char *p; ++ int i, j, k; ++ ++ if (!path || path[0] == '/') return path; ++ ++ if (!getcwd(buf, PATH_MAX)) return NULL; ++ i = strlen(buf); ++ j = strlen(path); ++ k = i + 1 + j + 1; /* workdir + '/' + path + '\0' */ ++ if (i + j > PATH_MAX) { ++ errno = ERANGE; ++ return NULL; ++ } ++ if (!(p = malloc(k * sizeof(char*)))) return NULL; ++ ++ p[0] = '\0'; ++ ++ if (!strncat(p, buf, i)) return NULL; ++ if (!strncat(p, "/", 1)) return NULL; ++ if (!strncat(p, path, j)) return NULL; ++ return p; ++} +-- +2.39.3 (Apple Git-146) + diff --git a/patches/buildkit-direct-execve-v9.0/0004-linux-user-support-loading-scripts-with-shebang.patch b/patches/buildkit-direct-execve-v9.0/0004-linux-user-support-loading-scripts-with-shebang.patch new file mode 100644 index 00000000..d38d431d --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0004-linux-user-support-loading-scripts-with-shebang.patch @@ -0,0 +1,228 @@ +From e69d0b167d541ce9a075b0f38ee76caf26700d25 Mon Sep 17 00:00:00 2001 +From: Tibor Vass +Date: Thu, 18 Jun 2020 20:57:22 +0000 +Subject: [PATCH 4/7] linux-user: support loading scripts with shebang (#!) + +The interpreter is assumed to be compatible with the target architecture. + +The script loading logic is taken from Linux source code to match logic as closely as possible. + +An interpreter can itself be a script (#!/other.script), and thus load another interpreter. +This happens in a loop therefore the loading chain of interpreter-scripts is limited to 5 like in Linux. + +Warning: there might be issues with m68k, mips, and mips64 architectures +since the cpu_model returned by those architectures (see linux-user/$arch/target_elf.h) +is dependent on the ELF header of the payload, but in this case the payload +is a script and not a binary. + This could be fixed either by moving the loading logic or +parts of it to before the cpu_model is set, so that the final ELF binary is available. +An alternative fix is to avoid the loop altogether and call qemu binary again with different arguments. +The downside is that it would require one extra exec syscall per interpreter. + +Signed-off-by: Tibor Vass +Signed-off-by: Tonis Tiigi +--- + linux-user/elfload.c | 2 +- + linux-user/linuxload.c | 140 +++++++++++++++++++++++++++++++++++------ + linux-user/loader.h | 2 + + 3 files changed, 125 insertions(+), 19 deletions(-) + +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index 60cf55b36c..b1c9903ac1 100644 +--- a/linux-user/elfload.c ++++ b/linux-user/elfload.c +@@ -3811,10 +3811,10 @@ uint32_t get_elf_eflags(int fd) + return 0; + } + ret = read(fd, &ehdr, sizeof(ehdr)); ++ offset = lseek(fd, offset, SEEK_SET); /* reset seek regardless of error */ + if (ret < sizeof(ehdr)) { + return 0; + } +- offset = lseek(fd, offset, SEEK_SET); + if (offset == (off_t) -1) { + return 0; + } +diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c +index 37f132be4a..7e66ef0ab9 100644 +--- a/linux-user/linuxload.c ++++ b/linux-user/linuxload.c +@@ -142,7 +142,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, + struct target_pt_regs *regs, struct image_info *infop, + struct linux_binprm *bprm) + { +- int retval; ++ int retval, depth; + + bprm->src.fd = fdexec; + bprm->filename = (char *)filename; +@@ -151,25 +151,33 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, + bprm->envc = count(envp); + bprm->envp = envp; + +- retval = prepare_binprm(bprm); +- +- if (retval < 4) { +- return -ENOEXEC; +- } +- if (bprm->buf[0] == 0x7f +- && bprm->buf[1] == 'E' +- && bprm->buf[2] == 'L' +- && bprm->buf[3] == 'F') { +- retval = load_elf_binary(bprm, infop); ++ for (depth = 0; ; depth++) { ++ if (depth > 5) { ++ return -ELOOP; ++ } ++ retval = prepare_binprm(bprm); ++ if (retval >= 0) { ++ if (bprm->buf[0] == 0x7f ++ && bprm->buf[1] == 'E' ++ && bprm->buf[2] == 'L' ++ && bprm->buf[3] == 'F') { ++ retval = load_elf_binary(bprm, infop); + #if defined(TARGET_HAS_BFLT) +- } else if (bprm->buf[0] == 'b' +- && bprm->buf[1] == 'F' +- && bprm->buf[2] == 'L' +- && bprm->buf[3] == 'T') { +- retval = load_flt_binary(bprm, infop); ++ } else if (bprm->buf[0] == 'b' ++ && bprm->buf[1] == 'F' ++ && bprm->buf[2] == 'L' ++ && bprm->buf[3] == 'T') { ++ retval = load_flt_binary(bprm, infop); + #endif +- } else { +- return -ENOEXEC; ++ } else if (bprm->buf[0] == '#' ++ && bprm->buf[1] == '!') { ++ retval = load_script(bprm); ++ if (retval >= 0) continue; ++ } else { ++ return -ENOEXEC; ++ } ++ } ++ break; + } + if (retval < 0) { + return retval; +@@ -180,6 +188,102 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, + return 0; + } + ++static inline bool spacetab(char c) { return c == ' ' || c == '\t'; } ++static inline const char *next_non_spacetab(const char *first, const char *last) ++{ ++ for (; first <= last; first++) ++ if (!spacetab(*first)) ++ return first; ++ return NULL; ++} ++static inline const char *next_terminator(const char *first, const char *last) ++{ ++ for (; first <= last; first++) ++ if (spacetab(*first) || !*first) ++ return first; ++ return NULL; ++} ++ ++/* ++ * Reads the interpreter (shebang #!) line and modifies bprm object accordingly ++ * This is a modified version of Linux's load_script function. ++*/ ++int load_script(struct linux_binprm *bprm) ++{ ++ const char *i_name, *i_sep, *i_arg, *i_end, *buf_end; ++ int execfd, i, argc_delta; ++ ++ buf_end = bprm->buf + sizeof(bprm->buf) - 1; ++ i_end = (const char*)memchr(bprm->buf, '\n', sizeof(bprm->buf)); ++ if (!i_end) { ++ i_end = next_non_spacetab(bprm->buf + 2, buf_end); ++ if (!i_end) { ++ perror("script_prepare_binprm: no interpreter name found"); ++ return -ENOEXEC; /* Entire buf is spaces/tabs */ ++ } ++ /* ++ * If there is no later space/tab/NUL we must assume the ++ * interpreter path is truncated. ++ */ ++ if (!next_terminator(i_end, buf_end)) { ++ perror("script_prepare_binprm: truncated interpreter path"); ++ return -ENOEXEC; ++ } ++ i_end = buf_end; ++ } ++ /* Trim any trailing spaces/tabs from i_end */ ++ while (spacetab(i_end[-1])) ++ i_end--; ++ *((char *)i_end) = '\0'; ++ /* Skip over leading spaces/tabs */ ++ i_name = next_non_spacetab(bprm->buf+2, i_end); ++ if (!i_name || (i_name == i_end)) { ++ perror("script_prepare_binprm: no interpreter name found"); ++ return -ENOEXEC; /* No interpreter name found */ ++ } ++ ++ /* Is there an optional argument? */ ++ i_arg = NULL; ++ i_sep = next_terminator(i_name, i_end); ++ if (i_sep && (*i_sep != '\0')) { ++ i_arg = next_non_spacetab(i_sep, i_end); ++ *((char *)i_sep) = '\0'; ++ } ++ ++ /* ++ * OK, we've parsed out the interpreter name and ++ * (optional) argument. ++ * Splice in (1) the interpreter's name for argv[0] ++ * (2) (optional) argument to interpreter ++ * (3) filename of shell script (replace argv[0]) ++ * (4) user arguments (argv[1:]) ++ */ ++ ++ execfd = open(i_name, O_RDONLY); ++ if (execfd < 0) { ++ perror("script_prepare_binprm: could not open script"); ++ return -ENOEXEC; /* Could not open interpreter */ ++ } ++ ++ argc_delta = 1 /* extra filename */ + (i_arg ? 1 : 0); ++ bprm->argc += argc_delta; ++ bprm->argv = realloc(bprm->argv, sizeof(char*) * (bprm->argc + 1)); ++ ++ /* shift argv by argc_delta */ ++ for (i = bprm->argc; i >= argc_delta; i--) ++ bprm->argv[i] = bprm->argv[i-argc_delta]; ++ ++ bprm->argv[0] = (char *)strdup(i_name); ++ if (i_arg) ++ bprm->argv[1] = (char *)strdup(i_arg); ++ ++ bprm->src.fd = execfd; /* not closing fd as it is needed for the duration of the program */ ++ bprm->filename = (char *)strdup(i_name); /* replace filename with script interpreter */ ++ /* envc and envp are kept unchanged */ ++ ++ return 0; ++} ++ + bool imgsrc_read(void *dst, off_t offset, size_t len, + const ImageSource *img, Error **errp) + { +diff --git a/linux-user/loader.h b/linux-user/loader.h +index e102e6f410..c532d91016 100644 +--- a/linux-user/loader.h ++++ b/linux-user/loader.h +@@ -98,6 +98,8 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, + + extern unsigned long guest_stack_size; + ++int load_script(struct linux_binprm *bprm); ++ + #if defined(TARGET_S390X) || defined(TARGET_AARCH64) || defined(TARGET_ARM) + uint32_t get_elf_hwcap(void); + const char *elf_hwcap_str(uint32_t bit); +-- +2.39.3 (Apple Git-146) + diff --git a/patches/buildkit-direct-execve-v9.0/0005-set-script-path-as-argv0-in-shebang-handler.patch b/patches/buildkit-direct-execve-v9.0/0005-set-script-path-as-argv0-in-shebang-handler.patch new file mode 100644 index 00000000..f6004c14 --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0005-set-script-path-as-argv0-in-shebang-handler.patch @@ -0,0 +1,26 @@ +From 39f0697cb9d13d8630543209e5bf22148b32b7cb Mon Sep 17 00:00:00 2001 +From: Tonis Tiigi +Date: Thu, 26 Aug 2021 01:18:32 +0200 +Subject: [PATCH 5/7] set script path as argv0 in shebang handler + +Signed-off-by: Tonis Tiigi +--- + linux-user/linuxload.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c +index 7e66ef0ab9..71f9f46aea 100644 +--- a/linux-user/linuxload.c ++++ b/linux-user/linuxload.c +@@ -259,6 +259,8 @@ int load_script(struct linux_binprm *bprm) + * (4) user arguments (argv[1:]) + */ + ++ bprm->argv[0] = bprm->filename; ++ + execfd = open(i_name, O_RDONLY); + if (execfd < 0) { + perror("script_prepare_binprm: could not open script"); +-- +2.39.3 (Apple Git-146) + diff --git a/patches/buildkit-direct-execve-v9.0/0006-linux-user-use-GLib-to-remember-the-program-name.patch b/patches/buildkit-direct-execve-v9.0/0006-linux-user-use-GLib-to-remember-the-program-name.patch new file mode 100644 index 00000000..4465ee96 --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0006-linux-user-use-GLib-to-remember-the-program-name.patch @@ -0,0 +1,26 @@ +From 30bf474191b3f1aad6617c4527c5f936fadc87c6 Mon Sep 17 00:00:00 2001 +From: CrazyMax +Date: Wed, 3 May 2023 20:57:04 +0200 +Subject: [PATCH 6/7] linux-user: use GLib to remember the program name + +Signed-off-by: CrazyMax +--- + linux-user/syscall.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index c6de1303ae..d9067e1648 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -8514,7 +8514,7 @@ static int do_execv(CPUArchState *cpu_env, int dirfd, + * where qemu_progname is the error message prefix for qemu. + * Note: if pathname is relative, it will be prepended with the current working directory. + */ +- argp[0] = (char*)error_get_progname(); ++ argp[0] = (char*)g_get_prgname(); + argp[1] = (char*)"-0"; + argp[2] = (char*)lock_user_string(addr); + argp[3] = (char*)prepend_workdir_if_relative(p); +-- +2.39.3 (Apple Git-146) + diff --git a/patches/buildkit-direct-execve-v9.0/0007-fix-execvp-PATH-handling.patch b/patches/buildkit-direct-execve-v9.0/0007-fix-execvp-PATH-handling.patch new file mode 100644 index 00000000..8e11da26 --- /dev/null +++ b/patches/buildkit-direct-execve-v9.0/0007-fix-execvp-PATH-handling.patch @@ -0,0 +1,59 @@ +From 799398afc09f55c23877ee79e4ce9f41823e9faf Mon Sep 17 00:00:00 2001 +From: CrazyMax +Date: Wed, 3 May 2023 21:04:19 +0200 +Subject: [PATCH 7/7] fix execvp PATH handling + +When the execvp syscall is invoked, the system PATH should be searched +for the executable to invoke, with the first match in the PATH being +invoked. However, the call being modified to inject qemu breaks this +behaviour, as it's not till _after_ qemu is invoked that the presence or +executability is checked, which is too late. ENOENT and EACCESS aren't +returned from the execve call, which stops execvp looping over the PATH +and aborts the entire process. + +This is resolved by testing the target command prior to executing it via +qemu, returning the appropriate error codes. + +Signed-off-by: David Ackroyd +Signed-off-by: CrazyMax +--- + linux-user/syscall.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index d9067e1648..1bfe4b2f0d 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -8466,6 +8466,7 @@ static int do_execv(CPUArchState *cpu_env, int dirfd, + abi_ulong addr; + char **q; + void *p; ++ struct stat st; + + argc = 0; + +@@ -8523,6 +8524,21 @@ static int do_execv(CPUArchState *cpu_env, int dirfd, + goto execve_end; + } + ++ /* ++ * Check whether executable up front, as running once the qemu process is started these failures ++ * will happen internally there, and only exposed as a non-zero exit code for qemu. ++ */ ++ ret = get_errno(stat(argp[3], &st)); ++ if (is_error(ret)) { ++ ret = -host_to_target_errno(errno); ++ goto execve_end; ++ } ++ ++ if ((st.st_mode & S_IFDIR) || !(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) { ++ ret = TARGET_EACCES; ++ goto execve_end; ++ } ++ + /* copy guest argv1 onwards to host argv4 onwards */ + for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { +-- +2.39.3 (Apple Git-146) + diff --git a/test/dockerfiles/ejabberd/Dockerfile b/test/dockerfiles/ejabberd/Dockerfile index 4dce4f9d..cbe7dc41 100644 --- a/test/dockerfiles/ejabberd/Dockerfile +++ b/test/dockerfiles/ejabberd/Dockerfile @@ -1,4 +1,5 @@ FROM alpine:3.15.4 AS build +ENV QEMU_STRACE=1 ARG REPOSITORY=https://github.com/processone/ejabberd.git #ARG VERSION=master ARG VERSION=99d9e315a3c0524d84197e63741790d5893c51f4 diff --git a/test/dockerfiles/pip-youtube-dl/Dockerfile b/test/dockerfiles/pip-youtube-dl/Dockerfile index 4792f3ff..44457170 100644 --- a/test/dockerfiles/pip-youtube-dl/Dockerfile +++ b/test/dockerfiles/pip-youtube-dl/Dockerfile @@ -3,6 +3,7 @@ # FROM python:3.9-alpine +ENV QEMU_STRACE=1 MAINTAINER kev RUN set -xe \ diff --git a/test/dockerfiles/postgis/Dockerfile b/test/dockerfiles/postgis/Dockerfile index 86566754..05192413 100644 --- a/test/dockerfiles/postgis/Dockerfile +++ b/test/dockerfiles/postgis/Dockerfile @@ -1,2 +1,3 @@ FROM postgis/postgis:15-master +ENV QEMU_STRACE=1 ENV POSTGRES_PASSWORD=password diff --git a/test/dockerfiles/tini/Dockerfile b/test/dockerfiles/tini/Dockerfile index 33682c56..54849b72 100644 --- a/test/dockerfiles/tini/Dockerfile +++ b/test/dockerfiles/tini/Dockerfile @@ -3,6 +3,7 @@ ARG TINI_VERSION="v0.19.0" FROM alpine:3.17 +ENV QEMU_STRACE=1 RUN apk add --no-cache file wget ARG TINI_VERSION ARG TARGETPLATFORM diff --git a/test/dockerfiles/webpack/Dockerfile b/test/dockerfiles/webpack/Dockerfile index 0faf7f50..be6478e1 100644 --- a/test/dockerfiles/webpack/Dockerfile +++ b/test/dockerfiles/webpack/Dockerfile @@ -1,4 +1,5 @@ FROM node:12-slim +ENV QEMU_STRACE=1 WORKDIR /js