X-Git-Url: http://git.pld-linux.org/?a=blobdiff_plain;f=qemu-user-execve.patch;h=3f538a95d61878e894c14319f245ca967b66a3ba;hb=f4914ae2c1dc5d0b97fcf04d486e63615711a315;hp=6f89ff37e44ae7b879980804f684e5e7efabd321;hpb=a5affa61b20ba97333f13cf99694087384f4513b;p=packages%2Fqemu.git diff --git a/qemu-user-execve.patch b/qemu-user-execve.patch index 6f89ff3..3f538a9 100644 --- a/qemu-user-execve.patch +++ b/qemu-user-execve.patch @@ -1,10 +1,28 @@ +Discussion: https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/ + https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7 -From 782e5bb77014ff136f7bb6133a911e5f53e914a7 Mon Sep 17 00:00:00 2001 +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 -Date: Thu, 24 Dec 2015 14:43:17 -0800 -Subject: [PATCH] linux-user: add option to intercept execve() syscalls +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 @@ -21,25 +39,17 @@ 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 --- - linux-user/main.c | 36 ++++++++++++++++ - linux-user/qemu.h | 1 + - linux-user/syscall.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 3 files changed, 153 insertions(+), 1 deletion(-) +v3 changes: + - rebase the patchset against current code diff --git a/linux-user/main.c b/linux-user/main.c -index 700724e..16cce85 100644 +index ee12035..5951279 100644 --- a/linux-user/main.c +++ b/linux-user/main.c -@@ -17,6 +17,7 @@ - * along with this program; if not, see . - */ - #include "qemu/osdep.h" -+#include - #include - #include - #include -@@ -75,6 +76,7 @@ static void usage(int exitcode); +@@ -79,6 +79,7 @@ static void usage(int exitcode); static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; @@ -47,59 +57,32 @@ index 700724e..16cce85 100644 /* 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) +@@ -3828,6 +3829,11 @@ 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); ++ qemu_execve_path = strdup(arg); +} + static void handle_arg_reserved_va(const char *arg) { char *p; -@@ -3909,6 +3943,8 @@ static const struct qemu_argument arg_table[] = { +@@ -3913,6 +3919,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()"}, ++ {"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 --git a/linux-user/qemu.h b/linux-user/qemu.h -index 26b0ba2..8270268 100644 +index bd90cc3..0d9b058 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h -@@ -137,6 +137,7 @@ void init_task_state(TaskState *ts); +@@ -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; @@ -107,22 +90,14 @@ index 26b0ba2..8270268 100644 extern unsigned long mmap_min_addr; /* ??? See if we can avoid exposing so much of the loader internals. */ -diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index 9517531..66446f7 100644 ---- a/linux-user/syscall.c -+++ b/linux-user/syscall.c -@@ -99,6 +99,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, - #include - #include - #include -+#include - #include "linux_loop.h" - #include "uname.h" - -@@ -5845,6 +5846,118 @@ static target_timer_t get_timer_id(abi_long arg) +--- qemu-2.12.0/linux-user/syscall.c~ 2018-04-30 21:43:39.000000000 +0300 ++++ qemu-2.12.0/linux-user/syscall.c 2018-04-30 21:46:36.362935706 +0300 +@@ -5854,6 +5854,109 @@ static target_timer_t get_timer_id(abi_long arg) 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[]) @@ -133,30 +108,19 @@ index 9517531..66446f7 100644 + 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); ++ return -ENOENT; + } + + 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); ++ return -ENOENT; + } + + close(fd); @@ -173,7 +137,7 @@ index 9517531..66446f7 100644 + buf[BINPRM_BUF_SIZE - 1] = '\0'; + cp = strchr(buf, '\n'); + if (cp == NULL) { -+ cp = buf + BINPRM_BUF_SIZE - 1; ++ cp = buf+BINPRM_BUF_SIZE-1; + } + *cp = '\0'; + while (cp > buf) { @@ -184,7 +148,7 @@ index 9517531..66446f7 100644 + break; + } + } -+ for (cp = buf + 2; (*cp == ' ') || (*cp == '\t'); cp++) { ++ for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++) { + /* nothing */ ; + } + if (*cp == '\0') { @@ -232,19 +196,22 @@ index 9517531..66446f7 100644 + new_argp[2] = argv[0]; + } + -+ return get_errno(execve(qemu_execve_path, new_argp, envp)); ++ 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_. */ -@@ -6104,7 +6217,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, - - if (!(p = lock_user_string(arg1))) - goto execve_efault; -- ret = get_errno(execve(p, argp, envp)); -+ -+ ret = qemu_execve(p, argp, envp); + static int target_to_host_cpu_mask(unsigned long *host_mask, + size_t host_size, + abi_ulong target_addr, +@@ -8257,7 +8257,12 @@ + * before the execve completes and makes it the other + * program's problem. + */ +- 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);