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