From 50e19119064cdab850e74f5ee168df73e2b0061e Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Tue, 8 Oct 2024 11:41:38 +0200 Subject: [PATCH] Hook realpath(3) for /proc/self/exe --- Makefile | 7 +++++-- src/termux-realpath.c | 21 +++++++++++++++++++++ tests/realpath.c | 20 ++++++++++++++++++++ tests/realpath.sh | 27 +++++++++++++++++++++++++++ tests/realpath.sh-expected | 1 + 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/termux-realpath.c create mode 100644 tests/realpath.c create mode 100755 tests/realpath.sh create mode 100644 tests/realpath.sh-expected diff --git a/Makefile b/Makefile index 82f61f8..1ce6c7c 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ CC ?= clang TERMUX_BASE_DIR ?= /data/data/com.termux/files CFLAGS += -Wall -Wextra -Werror -Wshadow -fvisibility=hidden -std=c23 -D__USE_GNU -C_SOURCE := src/termux-exec.c src/exec-variants.c src/termux-readlink.c +C_SOURCE := src/termux-exec.c src/exec-variants.c src/termux-readlink.c src/termux-realpath.c CLANG_FORMAT := clang-format --sort-includes --style="{ColumnLimit: 120}" $(C_SOURCE) tests/fexecve.c tests/system-uname.c tests/print-argv0.c tests/popen.c CLANG_TIDY ?= clang-tidy -TEST_BINARIES = tests/execl tests/exec-directory tests/fexecve tests/popen tests/system-uname tests/readlink-proc-self-exe +TEST_BINARIES = tests/execl tests/exec-directory tests/fexecve tests/popen tests/system-uname tests/readlink-proc-self-exe tests/realpath ifeq ($(SANITIZE),1) CFLAGS += -O1 -g -fsanitize=address -fno-omit-frame-pointer @@ -39,6 +39,9 @@ tests/system-uname: tests/system-uname.c tests/readlink-proc-self-exe: tests/readlink-proc-self-exe.c $(CC) $(CFLAGS) -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" $< -o $@ +tests/realpath: tests/realpath.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 $@ diff --git a/src/termux-realpath.c b/src/termux-realpath.c new file mode 100644 index 0000000..3d9ec1c --- /dev/null +++ b/src/termux-realpath.c @@ -0,0 +1,21 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +__attribute__((visibility("default"))) char *_Nullable realpath(const char *_Nonnull path, char *_Nullable resolved) { + char *(*orig_realpath)(const char *, char *); + orig_realpath = dlsym(RTLD_NEXT, "realpath"); + + if (strcmp(path, "/proc/self/exe") == 0) { + const char *termux_self_exe = getenv("TERMUX_EXEC__PROC_SELF_EXE"); + if (termux_self_exe) { + path = termux_self_exe; + } + } + + return orig_realpath(path, resolved); +} diff --git a/tests/realpath.c b/tests/realpath.c new file mode 100644 index 0000000..4ca5d72 --- /dev/null +++ b/tests/realpath.c @@ -0,0 +1,20 @@ +#define _POSIX_C_SOURCE 1 +#define _XOPEN_SOURCE 500 +#include +#include +#include + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "Wrong arguments\n"); + } + char buf[PATH_MAX]; + char *res = realpath(argv[1], buf); + if (res) { + printf("%s\n", buf); + } else { + perror("realpath()"); + exit(EXIT_FAILURE); + } + return 0; +} diff --git a/tests/realpath.sh b/tests/realpath.sh new file mode 100755 index 0000000..699b78b --- /dev/null +++ b/tests/realpath.sh @@ -0,0 +1,27 @@ +TMPDIR=$(mktemp -d) + +cp tests/realpath $TMPDIR + +cd $TMPDIR + +ACTUAL_PATH_TO_SELF=$(./realpath /proc/self/exe) +EXPECTED_PATH_TO_SELF=$TMPDIR/realpath + +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 + +ACTUAL_PATH_TO_SELF=$(./realpath /$TMPDIR) +EXPECTED_PATH_TO_SELF=$TMPDIR + +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 + +cd - > /dev/null + +rm -rf $TMPDIR + +echo ok diff --git a/tests/realpath.sh-expected b/tests/realpath.sh-expected new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/tests/realpath.sh-expected @@ -0,0 +1 @@ +ok