-
Notifications
You must be signed in to change notification settings - Fork 80
/
Copy path0003-linux-user-path-in-execve-should-be-relative-to-work.patch
103 lines (93 loc) · 3.6 KB
/
0003-linux-user-path-in-execve-should-be-relative-to-work.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
From 8fd15aa673a7241f8aeeb64fff5633b973913ae3 Mon Sep 17 00:00:00 2001
From: CrazyMax <[email protected]>
Date: Wed, 3 May 2023 20:54:37 +0200
Subject: [PATCH] linux-user: path in execve should be relative to working dir
Fixes regression introduced in parent commit where PATH handling was introduced.
When guest calls execve(filename, argp, envp) filename can be relative in which
case Linux makes it relative to the working directory.
However, since execve is now handled by exec-ing qemu process again, filename
would first get looked up in PATH in main() before calling host's execve.
With this change, if filename is relative and exists in working directory as
well as in PATH, working directory will get precedence over PATH if guest is
doing an execve syscall, but not if relative filename comes from qemu's argv.
Signed-off-by: Tibor Vass <[email protected]>
Signed-off-by: CrazyMax <[email protected]>
---
include/qemu/path.h | 1 +
linux-user/syscall.c | 9 +++++++--
util/path.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/include/qemu/path.h b/include/qemu/path.h
index c6292a9709..a81fb51e1f 100644
--- a/include/qemu/path.h
+++ b/include/qemu/path.h
@@ -3,5 +3,6 @@
void init_paths(const char *prefix);
const char *path(const char *pathname);
+const char *prepend_workdir_if_relative(const char *path);
#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 947af70611..0ce9f207be 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8444,12 +8444,17 @@ static int do_execveat(CPUArchState *cpu_env, int dirfd,
* execve(pathname, [argv0, argv1], envp)
* on the host, becomes:
* execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp)
- * where qemu_progname is the error message prefix for qemu
+ * where qemu_progname is the error message prefix for qemu.
+ * Note: if pathname is relative, it will be prepended with the current working directory.
*/
argp[0] = (char*)error_get_progname();
argp[1] = (char*)"-0";
argp[2] = (char*)lock_user_string(addr);
- argp[3] = p;
+ argp[3] = (char*)prepend_workdir_if_relative(p);
+ if (!argp[3]) {
+ ret = -host_to_target_errno(errno);
+ goto execve_end;
+ }
/* copy guest argv1 onwards to host argv4 onwards */
for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp; gp += sizeof(abi_ulong), q++) {
diff --git a/util/path.c b/util/path.c
index 8e174eb436..06fe2663b8 100644
--- a/util/path.c
+++ b/util/path.c
@@ -68,3 +68,35 @@ const char *path(const char *name)
qemu_mutex_unlock(&lock);
return ret;
}
+
+/* Prepends working directory if path is relative.
+ * If path is absolute, it is returned as-is without any allocation.
+ * Otherwise, caller is responsible to free returned path.
+ * Returns NULL and sets errno upon error.
+ * Note: realpath is not called to let the kernel do the rest of the resolution.
+ */
+const char *prepend_workdir_if_relative(const char *path)
+{
+ char buf[PATH_MAX];
+ char *p;
+ int i, j, k;
+
+ if (!path || path[0] == '/') return path;
+
+ if (!getcwd(buf, PATH_MAX)) return NULL;
+ i = strlen(buf);
+ j = strlen(path);
+ k = i + 1 + j + 1; /* workdir + '/' + path + '\0' */
+ if (i + j > PATH_MAX) {
+ errno = ERANGE;
+ return NULL;
+ }
+ if (!(p = malloc(k * sizeof(char*)))) return NULL;
+
+ p[0] = '\0';
+
+ if (!strncat(p, buf, i)) return NULL;
+ if (!strncat(p, "/", 1)) return NULL;
+ if (!strncat(p, path, j)) return NULL;
+ return p;
+}
--
2.34.0