]> git.pld-linux.org Git - packages/qemu.git/blame - qemu-user-execve.patch
- updated to 8.0.5; virtiofsd is no longer included, external project can be used
[packages/qemu.git] / qemu-user-execve.patch
CommitLineData
f1a1313b 1Discussion:
a5affa61 2https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/
f1a1313b 3
a5affa61
ER
4https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7
5
102e18f7
ER
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
a5affa61 18From: Petros Angelatos <petrosagg@resin.io>
102e18f7
ER
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
a5affa61
ER
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>
102e18f7
ER
42Tested-by: Laurent Vivier <laurent@vivier.eu>
43Reviewed-by: Laurent Vivier <laurent@vivier.eu>
a5affa61 44---
102e18f7
ER
45v3 changes:
46 - rebase the patchset against current code
47
f1a1313b
ER
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
8806a92d 52@@ -123,6 +123,7 @@ static void usage(int exitcode);
a5affa61
ER
53
54 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
55 const char *qemu_uname_release;
56+const char *qemu_execve_path;
57
8806a92d 58 #if !defined(TARGET_DEFAULT_STACK_SIZE)
a5affa61 59 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
8806a92d 60@@ -362,6 +363,11 @@ static void handle_arg_guest_base(const
92618e32 61 have_guest_base = true;
a5affa61
ER
62 }
63
64+static void handle_arg_execve(const char *arg)
65+{
f1a1313b 66+ qemu_execve_path = strdup(arg);
a5affa61
ER
67+}
68+
69 static void handle_arg_reserved_va(const char *arg)
70 {
71 char *p;
8806a92d 72@@ -464,6 +470,8 @@ static const struct qemu_argument arg_ta
a5affa61
ER
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'"},
f1a1313b
ER
76+ {"execve", "QEMU_EXECVE", true, handle_arg_execve,
77+ "path", "use interpreter at 'path' when a process calls execve()"},
a5affa61
ER
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,
f6b5cdb2
JB
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);
a5affa61
ER
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
f6b5cdb2 90 typedef struct IOCTLEntry IOCTLEntry;
cc59f32b
JB
91--- qemu-8.0.5/linux-user/syscall.c.orig 2023-09-21 22:19:33.000000000 +0200
92+++ qemu-8.0.5/linux-user/syscall.c 2024-04-28 08:04:44.168009553 +0200
93@@ -8408,6 +8408,109 @@ static int do_openat(CPUArchState *cpu_e
94 return safe_openat(dirfd, path(pathname), flags, mode);
a5affa61
ER
95 }
96
f1a1313b
ER
97+#define BINPRM_BUF_SIZE 128
98+
a5affa61
ER
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+
a5affa61
ER
109+ for (argc = 0; argv[argc] != NULL; argc++) {
110+ /* nothing */ ;
111+ }
112+
113+ fd = open(filename, O_RDONLY);
114+ if (fd == -1) {
f1a1313b 115+ return -ENOENT;
a5affa61
ER
116+ }
117+
118+ ret = read(fd, buf, BINPRM_BUF_SIZE);
119+ if (ret == -1) {
120+ close(fd);
f1a1313b 121+ return -ENOENT;
a5affa61
ER
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) {
f1a1313b 138+ cp = buf+BINPRM_BUF_SIZE-1;
a5affa61
ER
139+ }
140+ *cp = '\0';
141+ while (cp > buf) {
142+ cp--;
143+ if ((*cp == ' ') || (*cp == '\t')) {
144+ *cp = '\0';
145+ } else {
146+ break;
147+ }
148+ }
f1a1313b 149+ for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++) {
a5affa61
ER
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+
99df371e 197+ return get_errno(safe_execve(qemu_execve_path, new_argp, envp));
a5affa61
ER
198+}
199+
cc59f32b
JB
200 static int do_execv(CPUArchState *cpu_env, int dirfd,
201 abi_long pathname, abi_long guest_argp,
202 abi_long guest_envp, int flags, bool is_execveat)
203@@ -8493,9 +8596,12 @@ static int do_execv(CPUArchState *cpu_en
204 if (is_proc_myself(p, "exe")) {
205 exe = exec_path;
206 }
207- ret = is_execveat
208- ? safe_execveat(dirfd, exe, argp, envp, flags)
209- : safe_execve(exe, argp, envp);
210+ if (is_execveat)
211+ ret = safe_execveat(dirfd, exe, argp, envp, flags);
212+ else if (qemu_execve_path && *qemu_execve_path)
213+ ret = qemu_execve(exe, argp, envp);
214+ else
215+ ret = safe_execve(exe, argp, envp);
216 ret = get_errno(ret);
217
218 unlock_user(p, pathname, 0);
This page took 0.065115 seconds and 4 git commands to generate.