]> git.pld-linux.org Git - packages/qemu.git/blame_incremental - qemu-user-execve.patch
- updated to 6.2.0; -system-moxie is gone
[packages/qemu.git] / qemu-user-execve.patch
... / ...
CommitLineData
1Discussion:
2https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/
3
4https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7
5
6https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7#commitcomment-17193923
7It 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.
8
9[1] https://patchwork.ozlabs.org/patch/569452/
10[2] https://patchwork.ozlabs.org/patch/573877/
11[3] https://patchwork.ozlabs.org/patch/582756/
12
13From patchwork Mon Feb 15 05:51:47 2016
14Content-Type: text/plain; charset="utf-8"
15MIME-Version: 1.0
16Content-Transfer-Encoding: 7bit
17Subject: [v3] linux-user: add option to intercept execve() syscalls
18From: Petros Angelatos <petrosagg@resin.io>
19X-Patchwork-Id: 582756
20Message-Id: <1455515507-26877-1-git-send-email-petrosagg@resin.io>
21To: qemu-devel@nongnu.org
22Cc: lucas.kaldstrom@hotmail.co.uk, peter.maydell@linaro.org,
23 riku.voipio@iki.fi,
24 laurent@vivier.eu, Petros Angelatos <petrosagg@resin.io>
25Date: Sun, 14 Feb 2016 21:51:47 -0800
26
27In order for one to use QEMU user mode emulation under a chroot, it is
28required to use binfmt_misc. This can be avoided by QEMU never doing a
29raw execve() to the host system.
30
31Introduce a new option, -execve, that uses the current QEMU interpreter
32to intercept execve().
33
34qemu_execve() will prepend the interpreter path , similar to what
35binfmt_misc would do, and then pass the modified execve() to the host.
36
37It is necessary to parse hashbang scripts in that function otherwise
38the kernel will try to run the interpreter of a script without QEMU and
39get an invalid exec format error.
40
41Signed-off-by: Petros Angelatos <petrosagg@resin.io>
42Tested-by: Laurent Vivier <laurent@vivier.eu>
43Reviewed-by: Laurent Vivier <laurent@vivier.eu>
44---
45v3 changes:
46 - rebase the patchset against current code
47
48diff --git a/linux-user/main.c b/linux-user/main.c
49index ee12035..5951279 100644
50--- a/linux-user/main.c
51+++ b/linux-user/main.c
52@@ -79,6 +79,7 @@ static void usage(int exitcode);
53
54 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
55 const char *qemu_uname_release;
56+const char *qemu_execve_path;
57
58 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
59 we allocate a bigger stack. Need a better solution, for example
60@@ -3828,6 +3829,11 @@ static void handle_arg_guest_base(const char *arg)
61 have_guest_base = true;
62 }
63
64+static void handle_arg_execve(const char *arg)
65+{
66+ qemu_execve_path = strdup(arg);
67+}
68+
69 static void handle_arg_reserved_va(const char *arg)
70 {
71 char *p;
72@@ -3913,6 +3919,8 @@ static const struct qemu_argument arg_table[] = {
73 "uname", "set qemu uname release string to 'uname'"},
74 {"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
75 "address", "set guest_base address to 'address'"},
76+ {"execve", "QEMU_EXECVE", true, handle_arg_execve,
77+ "path", "use interpreter at 'path' when a process calls execve()"},
78 {"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
79 "size", "reserve 'size' bytes for guest virtual address space"},
80 {"d", "QEMU_LOG", true, handle_arg_log,
81--- qemu-6.2.0/linux-user/user-internals.h.orig
82+++ qemu-6.2.0/linux-user/user-internals.h
83@@ -28,6 +28,7 @@ void init_task_state(TaskState *ts);
84 void task_settid(TaskState *);
85 void stop_all_tasks(void);
86 extern const char *qemu_uname_release;
87+extern const char *qemu_execve_path;
88 extern unsigned long mmap_min_addr;
89
90 typedef struct IOCTLEntry IOCTLEntry;
91--- qemu-2.12.0/linux-user/syscall.c~ 2018-04-30 21:43:39.000000000 +0300
92+++ qemu-2.12.0/linux-user/syscall.c 2018-04-30 21:46:36.362935706 +0300
93@@ -5854,6 +5854,109 @@ static target_timer_t get_timer_id(abi_long arg)
94 return timerid;
95 }
96
97+#define BINPRM_BUF_SIZE 128
98+
99+/* qemu_execve() Must return target values and target errnos. */
100+static abi_long qemu_execve(char *filename, char *argv[],
101+ char *envp[])
102+{
103+ char *i_arg = NULL, *i_name = NULL;
104+ char **new_argp;
105+ int argc, fd, ret, i, offset = 3;
106+ char *cp;
107+ char buf[BINPRM_BUF_SIZE];
108+
109+ for (argc = 0; argv[argc] != NULL; argc++) {
110+ /* nothing */ ;
111+ }
112+
113+ fd = open(filename, O_RDONLY);
114+ if (fd == -1) {
115+ return -ENOENT;
116+ }
117+
118+ ret = read(fd, buf, BINPRM_BUF_SIZE);
119+ if (ret == -1) {
120+ close(fd);
121+ return -ENOENT;
122+ }
123+
124+ close(fd);
125+
126+ /* adapted from the kernel
127+ * https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_script.c
128+ */
129+ if ((buf[0] == '#') && (buf[1] == '!')) {
130+ /*
131+ * This section does the #! interpretation.
132+ * Sorta complicated, but hopefully it will work. -TYT
133+ */
134+
135+ buf[BINPRM_BUF_SIZE - 1] = '\0';
136+ cp = strchr(buf, '\n');
137+ if (cp == NULL) {
138+ cp = buf+BINPRM_BUF_SIZE-1;
139+ }
140+ *cp = '\0';
141+ while (cp > buf) {
142+ cp--;
143+ if ((*cp == ' ') || (*cp == '\t')) {
144+ *cp = '\0';
145+ } else {
146+ break;
147+ }
148+ }
149+ for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++) {
150+ /* nothing */ ;
151+ }
152+ if (*cp == '\0') {
153+ return -ENOEXEC; /* No interpreter name found */
154+ }
155+ i_name = cp;
156+ i_arg = NULL;
157+ for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
158+ /* nothing */ ;
159+ }
160+ while ((*cp == ' ') || (*cp == '\t')) {
161+ *cp++ = '\0';
162+ }
163+ if (*cp) {
164+ i_arg = cp;
165+ }
166+
167+ if (i_arg) {
168+ offset = 5;
169+ } else {
170+ offset = 4;
171+ }
172+ }
173+
174+ new_argp = alloca((argc + offset + 1) * sizeof(void *));
175+
176+ /* Copy the original arguments with offset */
177+ for (i = 0; i < argc; i++) {
178+ new_argp[i + offset] = argv[i];
179+ }
180+
181+ new_argp[0] = strdup(qemu_execve_path);
182+ new_argp[1] = strdup("-0");
183+ new_argp[offset] = filename;
184+ new_argp[argc + offset] = NULL;
185+
186+ if (i_name) {
187+ new_argp[2] = i_name;
188+ new_argp[3] = i_name;
189+
190+ if (i_arg) {
191+ new_argp[4] = i_arg;
192+ }
193+ } else {
194+ new_argp[2] = argv[0];
195+ }
196+
197+ return get_errno(safe_execve(qemu_execve_path, new_argp, envp));
198+}
199+
200 static int target_to_host_cpu_mask(unsigned long *host_mask,
201 size_t host_size,
202 abi_ulong target_addr,
203@@ -8257,7 +8257,12 @@
204 * before the execve completes and makes it the other
205 * program's problem.
206 */
207- ret = get_errno(safe_execve(p, argp, envp));
208+ if (qemu_execve_path && *qemu_execve_path) {
209+ ret = get_errno(qemu_execve(p, argp, envp));
210+ } else {
211+ ret = get_errno(safe_execve(p, argp, envp));
212+ }
213+
214 unlock_user(p, arg1, 0);
215
216 goto execve_end;
This page took 0.030561 seconds and 4 git commands to generate.