X-Git-Url: https://git.tld-linux.org/?p=packages%2Fqemu.git;a=blobdiff_plain;f=qemu-user-execve.patch;h=3f538a95d61878e894c14319f245ca967b66a3ba;hp=78c0e57e89af77d79623055e370778f720dca8a1;hb=HEAD;hpb=0652bf3563918ba890a7eb4a6c20bd7d78938832 diff --git a/qemu-user-execve.patch b/qemu-user-execve.patch deleted file mode 100644 index 78c0e57..0000000 --- a/qemu-user-execve.patch +++ /dev/null @@ -1,261 +0,0 @@ -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 -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 -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 -Tested-by: Laurent Vivier -Reviewed-by: Laurent Vivier ---- -v3 changes: - - rebase the patchset against current code - ---- qemu-2.7.0/linux-user/main.c~ 2016-09-26 12:07:20.000000000 +0300 -+++ qemu-2.7.0/linux-user/main.c 2016-09-26 12:09:24.258470304 +0300 -@@ -18,6 +18,7 @@ - */ - #include "qemu/osdep.h" - #include "qemu-version.h" -+#include - #include - #include - -@@ -75,6 +76,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; - - /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so - we allocate a bigger stack. Need a better solution, for example -@@ -3824,6 +3826,38 @@ static void handle_arg_guest_base(const char *arg) - have_guest_base = 1; - } - -+static void handle_arg_execve(const char *arg) -+{ -+ const char *execfn; -+ char buf[PATH_MAX]; -+ char *ret; -+ int len; -+ -+ /* try getauxval() */ -+ execfn = (const char *) getauxval(AT_EXECFN); -+ -+ if (execfn != 0) { -+ ret = realpath(execfn, buf); -+ -+ if (ret != NULL) { -+ qemu_execve_path = strdup(buf); -+ return; -+ } -+ } -+ -+ /* try /proc/self/exe */ -+ len = readlink("/proc/self/exe", buf, sizeof(buf) - 1); -+ -+ if (len != -1) { -+ buf[len] = '\0'; -+ qemu_execve_path = strdup(buf); -+ return; -+ } -+ -+ fprintf(stderr, "qemu_execve: unable to determine intepreter's path\n"); -+ exit(EXIT_FAILURE); -+} -+ - static void handle_arg_reserved_va(const char *arg) - { - char *p; -@@ -3909,6 +3943,8 @@ static const struct qemu_argument arg_table[] = { - "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", false, handle_arg_execve, -+ "", "use this interpreter 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 --git a/linux-user/qemu.h b/linux-user/qemu.h -index bd90cc3..0d9b058 100644 ---- a/linux-user/qemu.h -+++ b/linux-user/qemu.h -@@ -140,6 +140,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; - - /* ??? See if we can avoid exposing so much of the loader internals. */ ---- qemu-2.7.0/linux-user/syscall.c~ 2016-09-26 12:10:36.000000000 +0300 -+++ qemu-2.7.0/linux-user/syscall.c 2016-09-26 12:13:54.312490312 +0300 -@@ -99,6 +99,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -5842,6 +5843,118 @@ static target_timer_t get_timer_id(abi_long arg) - return timerid; - } - -+/* 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]; -+ -+ /* normal execve case */ -+ if (qemu_execve_path == NULL || *qemu_execve_path == 0) { -+ return get_errno(execve(filename, argv, envp)); -+ } -+ -+ for (argc = 0; argv[argc] != NULL; argc++) { -+ /* nothing */ ; -+ } -+ -+ fd = open(filename, O_RDONLY); -+ if (fd == -1) { -+ return get_errno(fd); -+ } -+ -+ ret = read(fd, buf, BINPRM_BUF_SIZE); -+ if (ret == -1) { -+ close(fd); -+ return get_errno(ret); -+ } -+ -+ /* if we have less than 2 bytes, we can guess it is not executable */ -+ if (ret < 2) { -+ close(fd); -+ return -host_to_target_errno(ENOEXEC); -+ } -+ -+ 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)); -+} -+ - /* do_syscall() should always have a single exit point at the end so - that actions, such as logging of syscall results, can be performed. - All errnos that do_syscall() returns must be -TARGET_. */ -@@ -7703,7 +7703,7 @@ - * before the execve completes and makes it the other - * program's problem. - */ -- ret = get_errno(safe_execve(p, argp, envp)); -+ ret = qemu_execve(p, argp, envp); - unlock_user(p, arg1, 0); - - goto execve_end;