From f272aaa8886e2db3c208df32889ee4e2fe04169b Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Wed, 18 Sep 2024 11:37:36 +0200 Subject: [PATCH] Apply realpath(3) when hooking readlink("/proc/self/exe") --- .gitignore | 1 + Makefile | 5 ++++- src/termux-readlink.c | 5 +++++ tests/popen.c | 12 ++++++------ tests/readlink-proc-self-exe.c | 16 ++++++++++++++++ tests/readlink-proc-self-exe.expected | 1 + tests/readlink-proc-self-exe.sh | 22 ++++++++++++++++++++++ 7 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 tests/readlink-proc-self-exe.c create mode 100644 tests/readlink-proc-self-exe.expected create mode 100755 tests/readlink-proc-self-exe.sh diff --git a/.gitignore b/.gitignore index 8caebef..f85e6ed 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ test-binary tests/fexecve tests/popen tests/system-uname +tests/readlink-proc-self-exe diff --git a/Makefile b/Makefile index 3fe778b..43f6ca6 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ tests/popen: tests/popen.c tests/system-uname: tests/system-uname.c $(CC) $(CFLAGS) -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" $< -o $@ +tests/readlink-proc-self-exe: tests/readlink-proc-self-exe.c + $(CC) $(CFLAGS) -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" $< -o $@ + $(TERMUX_BASE_DIR)/usr/bin/termux-exec-test-print-argv0: tests/print-argv0.c $(CC) $(CFLAGS) $< -o $@ @@ -43,7 +46,7 @@ on-device-tests: make clean ASAN_OPTIONS=symbolize=0,detect_leaks=0 make on-device-tests-internal -on-device-tests-internal: libtermux-exec.so tests/fexecve tests/popen tests/system-uname $(TERMUX_BASE_DIR)/usr/bin/termux-exec-test-print-argv0 +on-device-tests-internal: libtermux-exec.so tests/fexecve tests/popen tests/system-uname tests/readlink-proc-self-exe $(TERMUX_BASE_DIR)/usr/bin/termux-exec-test-print-argv0 @LD_PRELOAD=${CURDIR}/libtermux-exec.so ./run-tests.sh format: diff --git a/src/termux-readlink.c b/src/termux-readlink.c index 63a50d2..9edf2db 100644 --- a/src/termux-readlink.c +++ b/src/termux-readlink.c @@ -10,6 +10,11 @@ __attribute__((visibility("default"))) ssize_t readlink(const char *restrict pat if (strcmp(pathname, "/proc/self/exe") == 0) { const char *termux_self_exe = getenv("TERMUX_EXEC__PROC_SELF_EXE"); if (termux_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); diff --git a/tests/popen.c b/tests/popen.c index 5126ed9..a5cbf20 100644 --- a/tests/popen.c +++ b/tests/popen.c @@ -1,10 +1,10 @@ #include int main() { - FILE* file = popen("uname", "r"); - char buffer[101]; - fscanf(file, "%100s", buffer); - pclose(file); - printf("%s\n", buffer); - return 0; + FILE *file = popen("uname", "r"); + char buffer[101]; + fscanf(file, "%100s", buffer); + pclose(file); + printf("%s\n", buffer); + return 0; } diff --git a/tests/readlink-proc-self-exe.c b/tests/readlink-proc-self-exe.c new file mode 100644 index 0000000..16a1f35 --- /dev/null +++ b/tests/readlink-proc-self-exe.c @@ -0,0 +1,16 @@ +#include +#include + +int main() { + char buf[PATH_MAX + 1]; + + ssize_t res = readlink("/proc/self/exe", buf, PATH_MAX); + if (res < 0) { + perror("readlink()"); + return 1; + } + buf[res] = 0; + printf("%s\n", buf); + return 0; +} + diff --git a/tests/readlink-proc-self-exe.expected b/tests/readlink-proc-self-exe.expected new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/tests/readlink-proc-self-exe.expected @@ -0,0 +1 @@ +ok diff --git a/tests/readlink-proc-self-exe.sh b/tests/readlink-proc-self-exe.sh new file mode 100755 index 0000000..006a6cd --- /dev/null +++ b/tests/readlink-proc-self-exe.sh @@ -0,0 +1,22 @@ +TMPDIR=$(mktemp -d) + +cp tests/readlink-proc-self-exe $TMPDIR + +cd $TMPDIR + +ACTUAL_PATH_TO_SELF=$(./readlink-proc-self-exe) +EXPECTED_PATH_TO_SELF=$TMPDIR/readlink-proc-self-exe + +if [ "$ACTUAL_PATH_TO_SELF" != "$EXPECTED_PATH_TO_SELF" ]; then + echo "ERROR(1): Expected '$EXPECTED_PATH_TO_SELF', was '$ACTUAL_PATH_TO_SELF'" + exit 1 +fi + +ln -s readlink-proc-self-exe symlinked-binary +ACTUAL_PATH_TO_SELF=$(./symlinked-binary) +if [ "$ACTUAL_PATH_TO_SELF" != "$EXPECTED_PATH_TO_SELF" ]; then + echo "ERROR(2): Expected '$EXPECTED_PATH_TO_SELF', was '$ACTUAL_PATH_TO_SELF'" + exit 1 +fi + +echo ok