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