diff --git a/Makefile b/Makefile index 43f6ca6..09d147b 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ on-device-tests-internal: libtermux-exec.so tests/fexecve tests/popen tests/syst @LD_PRELOAD=${CURDIR}/libtermux-exec.so ./run-tests.sh format: - $(CLANG_FORMAT) -i $(C_SOURCE) + $(CLANG_FORMAT) -i $(C_SOURCE) tests/*.c check: $(CLANG_FORMAT) --dry-run $(C_SOURCE) diff --git a/src/termux-exec.c b/src/termux-exec.c index 5c4c15c..0407cc8 100644 --- a/src/termux-exec.c +++ b/src/termux-exec.c @@ -351,8 +351,8 @@ __attribute__((visibility("default"))) int execve(const char *executable_path, c char const *executable_path_resolved = realpath(executable_path, executable_path_resolved_buffer); char const *path_to_use = executable_path_resolved ? executable_path_resolved : executable_path; bool wrap_in_linker = (strstr(path_to_use, TERMUX_BASE_DIR) == path_to_use) - // /system/bin/sh is fine, it only uses libc++, libc, and libdl. - || (strcmp(path_to_use, "/system/bin/sh") == 0); + // /system/bin/sh is fine, it only uses libc++, libc, and libdl. + || (strcmp(path_to_use, "/system/bin/sh") == 0); // Avoid interfering with Android /system software by removing // LD_PRELOAD and LD_LIBRARY_PATH from env if executing something diff --git a/src/termux-readlink.c b/src/termux-readlink.c index 9edf2db..5e6fef6 100644 --- a/src/termux-readlink.c +++ b/src/termux-readlink.c @@ -1,4 +1,5 @@ #define _GNU_SOURCE +#include #include #include #include @@ -20,6 +21,42 @@ __attribute__((visibility("default"))) ssize_t readlink(const char *restrict pat memcpy(buf, termux_self_exe, bytes_to_copy); return bytes_to_copy; } + } else if (strncmp(pathname, "/proc/", strlen("/proc/")) == 0) { + // See if /proc/$PID/exe is being resolved. + size_t path_len = strlen(pathname); + if (pathname[path_len - 4] == '/' && pathname[path_len - 3] == 'e' && pathname[path_len - 2] == 'x' && + pathname[path_len - 1] == 'e' && path_len < 30) { + char environ_path_buf[PATH_MAX]; + memcpy(environ_path_buf, pathname, path_len - 3); + memcpy(environ_path_buf + (path_len - 3), "environ", sizeof("environ")); + int environ_fd = TEMP_FAILURE_RETRY(open(environ_path_buf, O_RDONLY)); + if (environ_fd > 0) { + char environ_buf[16 * 4096]; + ssize_t environ_size = TEMP_FAILURE_RETRY(read(environ_fd, environ_buf, sizeof(environ_buf))); + close(environ_fd); + if (environ_size > 0) { + size_t start_offset = 0; + for (size_t i = 0; i < (size_t)environ_size; i++) { + if (environ_buf[i] == 0 && start_offset != i) { + if (strncmp(&environ_buf[start_offset], + "TERMUX_EXEC__PROC_SELF_EXE=", strlen("TERMUX_EXEC__PROC_SELF_EXE=")) == 0) { + char *termux_self_exe = &environ_buf[start_offset + strlen("TERMUX_EXEC__PROC_SELF_EXE=")]; + char resolved_path_buf[PATH_MAX]; + char *resolved_path = realpath(termux_self_exe, resolved_path_buf); + if (resolved_path) { + termux_self_exe = resolved_path_buf; + } + size_t termux_self_exe_len = strlen(termux_self_exe); + size_t bytes_to_copy = (termux_self_exe_len < bufsiz) ? termux_self_exe_len : bufsiz; + memcpy(buf, termux_self_exe, bytes_to_copy); + return bytes_to_copy; + } + start_offset = i + 1; + } + } + } + } + } } return syscall(SYS_readlinkat, AT_FDCWD, pathname, buf, bufsiz); diff --git a/tests/readlink-proc-self-exe.c b/tests/readlink-proc-self-exe.c index 465c024..f041eb2 100644 --- a/tests/readlink-proc-self-exe.c +++ b/tests/readlink-proc-self-exe.c @@ -1,6 +1,7 @@ #define _DEFAULT_SOURCE #include #include +#include #include int main() { @@ -11,8 +12,29 @@ int main() { perror("readlink()"); return 1; } + buf[res] = 0; printf("%s\n", buf); + + // Validate that reading /proc/$PID/exe gives the same result as /proc/self/exe + char *proc_pid_exe_path; + asprintf(&proc_pid_exe_path, "/proc/%ld/exe", (long)getpid()); + char pid_buf[PATH_MAX + 1]; + int fd = open(proc_pid_exe_path, O_RDONLY); + if (fd <= 0) { + perror("open()"); + return 1; + } + ssize_t pid_res = readlink(proc_pid_exe_path, pid_buf, PATH_MAX); + if (pid_res <= 0) { + perror("readlink()"); + return 1; + } + pid_buf[pid_res] = 0; + if (strcmp(buf, pid_buf) != 0) { + fprintf(stderr, "Mismatch - readlink(/proc/self/exe)='%s', readlink(/proc/$PID/exe)='%s'\n", buf, pid_buf); + return 1; + } + return 0; } -