+++ /dev/null
-Discussion:
-https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/
-
-https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7
-
-https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7#commitcomment-17193923
-It has gone through review[1][2][3] and I'm waiting for the maintainer of the linux-user subsystem to accept it in his tree.
-
-[1] https://patchwork.ozlabs.org/patch/569452/
-[2] https://patchwork.ozlabs.org/patch/573877/
-[3] https://patchwork.ozlabs.org/patch/582756/
-
-From patchwork Mon Feb 15 05:51:47 2016
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3] linux-user: add option to intercept execve() syscalls
-From: Petros Angelatos <petrosagg@resin.io>
-X-Patchwork-Id: 582756
-Message-Id: <1455515507-26877-1-git-send-email-petrosagg@resin.io>
-To: qemu-devel@nongnu.org
-Cc: lucas.kaldstrom@hotmail.co.uk, peter.maydell@linaro.org,
- riku.voipio@iki.fi,
- laurent@vivier.eu, Petros Angelatos <petrosagg@resin.io>
-Date: Sun, 14 Feb 2016 21:51:47 -0800
-
-In order for one to use QEMU user mode emulation under a chroot, it is
-required to use binfmt_misc. This can be avoided by QEMU never doing a
-raw execve() to the host system.
-
-Introduce a new option, -execve, that uses the current QEMU interpreter
-to intercept execve().
-
-qemu_execve() will prepend the interpreter path , similar to what
-binfmt_misc would do, and then pass the modified execve() to the host.
-
-It is necessary to parse hashbang scripts in that function otherwise
-the kernel will try to run the interpreter of a script without QEMU and
-get an invalid exec format error.
-
-Signed-off-by: Petros Angelatos <petrosagg@resin.io>
-Tested-by: Laurent Vivier <laurent@vivier.eu>
-Reviewed-by: Laurent Vivier <laurent@vivier.eu>
----
-v3 changes:
- - rebase the patchset against current code
-
-diff -urNpa qemu-7.2.0.orig/linux-user/main.c qemu-7.2.0/linux-user/main.c
---- qemu-7.2.0.orig/linux-user/main.c 2023-02-08 21:23:07.149156085 +0100
-+++ qemu-7.2.0/linux-user/main.c 2023-02-08 21:23:36.695149312 +0100
-@@ -123,6 +123,7 @@ static void usage(int exitcode);
-
- static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
- const char *qemu_uname_release;
-+const char *qemu_execve_path;
-
- #if !defined(TARGET_DEFAULT_STACK_SIZE)
- /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
-@@ -362,6 +363,11 @@ static void handle_arg_guest_base(const
- have_guest_base = true;
- }
-
-+static void handle_arg_execve(const char *arg)
-+{
-+ qemu_execve_path = strdup(arg);
-+}
-+
- static void handle_arg_reserved_va(const char *arg)
- {
- char *p;
-@@ -464,6 +470,8 @@ static const struct qemu_argument arg_ta
- "uname", "set qemu uname release string to 'uname'"},
- {"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
- "address", "set guest_base address to 'address'"},
-+ {"execve", "QEMU_EXECVE", true, handle_arg_execve,
-+ "path", "use interpreter at 'path' when a process calls execve()"},
- {"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
- "size", "reserve 'size' bytes for guest virtual address space"},
- {"d", "QEMU_LOG", true, handle_arg_log,
-diff -urNpa qemu-7.2.0.orig/linux-user/syscall.c qemu-7.2.0/linux-user/syscall.c
---- qemu-7.2.0.orig/linux-user/syscall.c 2023-02-08 21:23:07.150156084 +0100
-+++ qemu-7.2.0/linux-user/syscall.c 2023-02-08 21:28:50.327077355 +0100
-@@ -8378,6 +8378,109 @@ static target_timer_t get_timer_id(abi_l
- return timerid;
- }
-
-+#define BINPRM_BUF_SIZE 128
-+
-+/* qemu_execve() Must return target values and target errnos. */
-+static abi_long qemu_execve(char *filename, char *argv[],
-+ char *envp[])
-+{
-+ char *i_arg = NULL, *i_name = NULL;
-+ char **new_argp;
-+ int argc, fd, ret, i, offset = 3;
-+ char *cp;
-+ char buf[BINPRM_BUF_SIZE];
-+
-+ for (argc = 0; argv[argc] != NULL; argc++) {
-+ /* nothing */ ;
-+ }
-+
-+ fd = open(filename, O_RDONLY);
-+ if (fd == -1) {
-+ return -ENOENT;
-+ }
-+
-+ ret = read(fd, buf, BINPRM_BUF_SIZE);
-+ if (ret == -1) {
-+ close(fd);
-+ return -ENOENT;
-+ }
-+
-+ close(fd);
-+
-+ /* adapted from the kernel
-+ * https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_script.c
-+ */
-+ if ((buf[0] == '#') && (buf[1] == '!')) {
-+ /*
-+ * This section does the #! interpretation.
-+ * Sorta complicated, but hopefully it will work. -TYT
-+ */
-+
-+ buf[BINPRM_BUF_SIZE - 1] = '\0';
-+ cp = strchr(buf, '\n');
-+ if (cp == NULL) {
-+ cp = buf+BINPRM_BUF_SIZE-1;
-+ }
-+ *cp = '\0';
-+ while (cp > buf) {
-+ cp--;
-+ if ((*cp == ' ') || (*cp == '\t')) {
-+ *cp = '\0';
-+ } else {
-+ break;
-+ }
-+ }
-+ for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++) {
-+ /* nothing */ ;
-+ }
-+ if (*cp == '\0') {
-+ return -ENOEXEC; /* No interpreter name found */
-+ }
-+ i_name = cp;
-+ i_arg = NULL;
-+ for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
-+ /* nothing */ ;
-+ }
-+ while ((*cp == ' ') || (*cp == '\t')) {
-+ *cp++ = '\0';
-+ }
-+ if (*cp) {
-+ i_arg = cp;
-+ }
-+
-+ if (i_arg) {
-+ offset = 5;
-+ } else {
-+ offset = 4;
-+ }
-+ }
-+
-+ new_argp = alloca((argc + offset + 1) * sizeof(void *));
-+
-+ /* Copy the original arguments with offset */
-+ for (i = 0; i < argc; i++) {
-+ new_argp[i + offset] = argv[i];
-+ }
-+
-+ new_argp[0] = strdup(qemu_execve_path);
-+ new_argp[1] = strdup("-0");
-+ new_argp[offset] = filename;
-+ new_argp[argc + offset] = NULL;
-+
-+ if (i_name) {
-+ new_argp[2] = i_name;
-+ new_argp[3] = i_name;
-+
-+ if (i_arg) {
-+ new_argp[4] = i_arg;
-+ }
-+ } else {
-+ new_argp[2] = argv[0];
-+ }
-+
-+ return get_errno(safe_execve(qemu_execve_path, new_argp, envp));
-+}
-+
- static int target_to_host_cpu_mask(unsigned long *host_mask,
- size_t host_size,
- abi_ulong target_addr,
-@@ -8933,9 +9036,17 @@ static abi_long do_syscall1(CPUArchState
- * program's problem.
- */
- if (is_proc_myself(p, "exe")) {
-- ret = get_errno(safe_execve(exec_path, argp, envp));
-+ if (qemu_execve_path && *qemu_execve_path) {
-+ ret = get_errno(qemu_execve(exec_path, argp, envp));
-+ } else {
-+ ret = get_errno(safe_execve(exec_path, argp, envp));
-+ }
- } else {
-- ret = get_errno(safe_execve(p, argp, envp));
-+ if (qemu_execve_path && *qemu_execve_path) {
-+ ret = get_errno(qemu_execve(p, argp, envp));
-+ } else {
-+ ret = get_errno(safe_execve(p, argp, envp));
-+ }
- }
- unlock_user(p, arg1, 0);
-
-diff -urNpa qemu-7.2.0.orig/linux-user/user-internals.h qemu-7.2.0/linux-user/user-internals.h
---- qemu-7.2.0.orig/linux-user/user-internals.h 2023-02-08 21:23:07.148156085 +0100
-+++ qemu-7.2.0/linux-user/user-internals.h 2023-02-08 21:23:36.697149312 +0100
-@@ -27,6 +27,7 @@ void init_task_state(TaskState *ts);
- void task_settid(TaskState *);
- void stop_all_tasks(void);
- extern const char *qemu_uname_release;
-+extern const char *qemu_execve_path;
- extern unsigned long mmap_min_addr;
-
- typedef struct IOCTLEntry IOCTLEntry;