Skip to content

Commit 7279c61

Browse files
committed
Do not clean environment when executing /system/bin/sh
Cleaning the environment from LD_PRELOAD when executing /system/bin/sh breaks things such as `popen(3)` and `system(3)`.
1 parent dc28ec6 commit 7279c61

13 files changed

+71
-21
lines changed

.github/workflows/ci.yml

+13-4
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,24 @@ jobs:
1212
steps:
1313
- uses: actions/checkout@v4
1414
- uses: Homebrew/actions/setup-homebrew@master
15+
- uses: nttld/setup-ndk@v1
16+
id: setup-ndk
17+
with:
18+
ndk-version: r26d
19+
link-to-sdk: true
1520
- run: brew install clang-format
16-
- run: make CC=clang
17-
- run: make check CC=clang
18-
- run: make unit-test CC=clang
21+
- run: make CC="${ANDROID_NDK_HOME}"/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang
22+
env:
23+
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
24+
- run: make check CLANG_TIDY="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang-tidy --extra-arg=--target=aarch64-linux-android29"
25+
env:
26+
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
27+
- run: make unit-test CC=clang HOST_BUILD=1
1928

2029
actionlint:
2130
runs-on: ubuntu-latest
2231
steps:
23-
- uses: actions/checkout@v4
32+
- uses: actions/checkout@v4
2433
- name: Download actionlint
2534
id: get_actionlint
2635
run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
*.deb
77
test-binary
88
tests/fexecve
9+
tests/popen
10+
tests/system-uname

Makefile

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CC ?= clang
22
TERMUX_BASE_DIR ?= /data/data/com.termux/files
3-
CFLAGS += -Wall -Wextra -Werror -Wshadow -fvisibility=hidden -std=c17 -Wno-error=tautological-pointer-compare
3+
CFLAGS += -Wall -Wextra -Werror -Wshadow -fvisibility=hidden -std=c17
44
C_SOURCE := src/termux-exec.c src/exec-variants.c
5-
CLANG_FORMAT := clang-format --sort-includes --style="{ColumnLimit: 120}" $(C_SOURCE)
5+
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
66
CLANG_TIDY ?= clang-tidy
77

88
ifeq ($(SANITIZE),1)
@@ -11,12 +11,22 @@ else
1111
CFLAGS += -O2
1212
endif
1313

14+
ifeq ($(HOST_BUILD),1)
15+
CFLAGS += -Wno-error=tautological-pointer-compare
16+
endif
17+
1418
libtermux-exec.so: $(C_SOURCE)
1519
$(CC) $(CFLAGS) $(LDFLAGS) $(C_SOURCE) -DTERMUX_PREFIX=\"$(TERMUX_PREFIX)\" -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" -shared -fPIC -o libtermux-exec.so
1620

1721
tests/fexecve: tests/fexecve.c
1822
$(CC) $(CFLAGS) -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" $< -o $@
1923

24+
tests/popen: tests/popen.c
25+
$(CC) $(CFLAGS) -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" $< -o $@
26+
27+
tests/system-uname: tests/system-uname.c
28+
$(CC) $(CFLAGS) -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" $< -o $@
29+
2030
$(TERMUX_BASE_DIR)/usr/bin/termux-exec-test-print-argv0: tests/print-argv0.c
2131
$(CC) $(CFLAGS) $< -o $@
2232

@@ -31,9 +41,9 @@ uninstall:
3141

3242
on-device-tests:
3343
make clean
34-
ASAN_OPTIONS=symbolize=0,detect_leaks=0 make SANITIZE=1 on-device-tests-internal
44+
ASAN_OPTIONS=symbolize=0,detect_leaks=0 make on-device-tests-internal
3545

36-
on-device-tests-internal: libtermux-exec.so tests/fexecve $(TERMUX_BASE_DIR)/usr/bin/termux-exec-test-print-argv0
46+
on-device-tests-internal: libtermux-exec.so tests/fexecve tests/popen tests/system-uname $(TERMUX_BASE_DIR)/usr/bin/termux-exec-test-print-argv0
3747
@LD_PRELOAD=${CURDIR}/libtermux-exec.so ./run-tests.sh
3848

3949
format:
@@ -43,8 +53,8 @@ check:
4353
$(CLANG_FORMAT) --dry-run $(C_SOURCE)
4454
$(CLANG_TIDY) -warnings-as-errors='*' $(C_SOURCE) -- -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\"
4555

46-
test-binary: $(C_SOURCE)
47-
$(CC) $(CFLAGS) $(LDFLAGS) $(C_SOURCE) -g -fsanitize=address -fno-omit-frame-pointer -DUNIT_TEST=1 -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" -o test-binary
56+
test-binary: src/termux-exec.c src/exec-variants.c
57+
$(CC) $(CFLAGS) $(LDFLAGS) $^ -g -fsanitize=address -fno-omit-frame-pointer -DUNIT_TEST=1 -DTERMUX_BASE_DIR=\"$(TERMUX_BASE_DIR)\" -o test-binary
4858

4959
deb: libtermux-exec.so
5060
termux-create-package termux-exec-debug.json

src/termux-exec.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,9 @@ __attribute__((visibility("default"))) int execve(const char *executable_path, c
350350
char executable_path_resolved_buffer[PATH_MAX];
351351
char const *executable_path_resolved = realpath(executable_path, executable_path_resolved_buffer);
352352
char const *path_to_use = executable_path_resolved ? executable_path_resolved : executable_path;
353-
bool wrap_in_linker = (strstr(path_to_use, TERMUX_BASE_DIR) == path_to_use);
353+
bool wrap_in_linker = (strstr(path_to_use, TERMUX_BASE_DIR) == path_to_use)
354+
// /system/bin/sh is fine, it only uses libc++, libc, and libdl.
355+
|| (strcmp(path_to_use, "/system/bin/sh") == 0);
354356

355357
// Avoid interfering with Android /system software by removing
356358
// LD_PRELOAD and LD_LIBRARY_PATH from env if executing something

tests/call-system-bin-sh.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/bin/sh
22

3-
/system/bin/sh -c 'echo LD_PRELOAD=$LD_PRELOAD TERMUX_EXEC__PROC_SELF_EXE=$TERMUX_EXEC__PROC_SELF_EXE'
3+
/system/bin/sh -c 'echo TERMUX_EXEC__PROC_SELF_EXE=$TERMUX_EXEC__PROC_SELF_EXE'

tests/call-system-bin-sh.sh-expected

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
LD_PRELOAD= TERMUX_EXEC__PROC_SELF_EXE=
1+
TERMUX_EXEC__PROC_SELF_EXE=/system/bin/sh

tests/fexecve.c

+11-8
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
#include <unistd.h>
44

55
int main() {
6-
const char* path_to_echo = TERMUX_BASE_DIR "/usr/bin/sh";
7-
int fd = open(path_to_echo, O_RDONLY);
8-
if (fd < 0) perror("open");
9-
char* args[] = {"sh", "-c", "echo hello fexecve", NULL};
10-
char* env[] = {NULL};
11-
fexecve(fd, args, env);
12-
perror("fexecve");
13-
return 0;
6+
const char *path_to_echo = TERMUX_BASE_DIR "/usr/bin/sh";
7+
int fd = open(path_to_echo, O_RDONLY);
8+
if (fd < 0) {
9+
perror("open");
10+
return 1;
11+
}
12+
char *args[] = {"sh", "-c", "echo hello fexecve", NULL};
13+
char *env[] = {NULL};
14+
fexecve(fd, args, env);
15+
perror("fexecve");
16+
return 0;
1417
}

tests/popen.c

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <stdio.h>
2+
3+
int main() {
4+
FILE* file = popen("uname", "r");
5+
char buffer[101];
6+
fscanf(file, "%100s", buffer);
7+
pclose(file);
8+
printf("%s\n", buffer);
9+
return 0;
10+
}

tests/popen.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
./tests/popen

tests/popen.sh-expected

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Linux

tests/system-uname.c

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdlib.h>
2+
3+
int main() {
4+
system("uname");
5+
return 0;
6+
}

tests/system-uname.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
./tests/system-uname

tests/system-uname.sh-expected

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Linux

0 commit comments

Comments
 (0)