Skip to content

Commit db738a1

Browse files
Added: Re-add system_linker_exec support initially added in 2fe4775 and removed in 1fac107 and libtermux-exec-linker-ld-preload.so $LD_PRELOAD library variant
- `lib/termux-exec_nos_c_tre/src/termux/api/termux_exec/ld_preload/direct/exec/ExecIntercept.c` from `libtermux-exec_nos_c_tre` handles the `system_linker_exec` now and uses `lib/termux-exec_nos_c_tre/src/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.c` to get whether `system_linker_exec` should be used based on the `isSystemLinkerExecEnabled()` and `shouldEnableSystemLinkerExecForFile()` functions. - The `libtermux-exec-linker-ld-preload.so` `$LD_PRELOAD` library variant has been added and is meant to intercept additional functions to solve other issues specific to `system_linker_exec` execution. The `libtermux-exec-direct-ld-preload.so` variant needs to support `system_linker_exec` as well as during package updates, before the `linker` variant is set as primary variant, the `direct` variant will get used for certain commands as it gets installed as the primary variant by default, and commands will fail if `system_linker_exec` is required to bypass execution restrictions. The primary `$LD_PRELOAD` library variant to be used is set by copying it to `$TERMUX__PREFIX/usr/lib/libtermux-exec-ld-preload.so` and this path is exported in `$LD_PRELOAD` by `login` script. This is done by the `postinst` script run during package installation, which runs `termux-exec-ld-preload-lib setup` to set the correct variant as per the execution type required for the Termux environment of the host device by running `termux-exec-system-linker-exec is-enabled` to check if `system_linker_exec` is to be enabled. - Added the `string` `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` environment variable for whether to use `system_linker_exec` if `TERMUX_EXEC__EXECVE_CALL__INTERCEPT` is enabled. If set to `disable`, `system_linker_exec` will be disabled. If set to `enable`, then `system_linker_exec` will be enabled but only if required. If set to `force`, then `system_linker_exec` will be force enabled even if not required and is supported. The default value is `enable`. Check `shouldEnableSystemLinkerExecForFile()` in `ExecIntercept.h` and `ExecIntercept.c` for more info and how its handled. Docs will be added in a later commit. The `system_linker_exec` will now engage for executable or interpreter paths that are under `TERMUX_APP__DATA_DIR` or `TERMUX_APP__LEGACY_DATA_DIR` instead of `TERMUX__ROOTFS` (`TERMUX_BASE_DIR`). - Use `android_buildVersionSdk_get()` from `libtermux-core_nos_c_tre` library to read `ANDROID__BUILD_VERSION_SDK` environment variable exported by Termux app to get Android build version sdk, and if its not set, then from the `android_get_device_api_level()` call provided by `<android/api-level.h>`, which gets it from the system properties, which should be slower. - Fix the environment `envp` being copied twice during `execve` for system bin paths, once for unsetting `LD_` variables and then to set `TERMUX_EXEC__PROC_SELF_EXE`. The `modifyExecEnv()` function now handles all changes to environment with a single copy. - Fix `TERMUX_EXEC__PROC_SELF_EXE` being set even if `system_linker_exec` is not being used on `targetSdkVersion <= 28`, etc, and also not being unset when going from `system_linker_exec` to direct execution like system binaries. Packages will be patched to detect if `system_linker_exec` is being used to modify their behaviour, which shouldn't be modified for direct execution.
1 parent 1fac107 commit db738a1

File tree

11 files changed

+999
-7
lines changed

11 files changed

+999
-7
lines changed

Makefile

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export override BUILD_OUTPUT_DIR := $(BUILD_DIR)/output# Default value: `build/o
6363
export override TMP_BUILD_OUTPUT_DIR := $(BUILD_OUTPUT_DIR)/tmp# Default value: `build/output/tmp`
6464

6565
export override PREFIX_BUILD_OUTPUT_DIR := $(BUILD_OUTPUT_DIR)/usr# Default value: `build/output/usr`
66+
export override BIN_BUILD_OUTPUT_DIR := $(PREFIX_BUILD_OUTPUT_DIR)/bin# Default value: `build/output/usr/bin`
6667
export override LIB_BUILD_OUTPUT_DIR := $(PREFIX_BUILD_OUTPUT_DIR)/lib# Default value: `build/output/usr/lib`
6768
export override LIBEXEC_BUILD_OUTPUT_DIR := $(PREFIX_BUILD_OUTPUT_DIR)/libexec# Default value: `build/output/usr/libexec`
6869
export override TESTS_BUILD_OUTPUT_DIR := $(LIBEXEC_BUILD_OUTPUT_DIR)/installed-tests/termux-exec# Default value: `build/output/usr/libexec/installed-tests/termux-exec`
@@ -236,7 +237,7 @@ CLANG_TIDY ?= clang-tidy
236237
# - https://www.gnu.org/software/make/manual/html_node/Parallel-Disable.html
237238
.NOTPARALLEL:
238239

239-
all: | pre-build build-libtermux-exec_nos_c_tre build-libtermux-exec-direct-ld-preload build-termux-exec-main-app
240+
all: | pre-build build-libtermux-exec_nos_c_tre build-libtermux-exec-direct-ld-preload build-libtermux-exec-linker-ld-preload build-termux-exec-main-app
240241
@printf "\ntermux-exec-package: %s\n" "Building packaging/debian/*"
241242
@mkdir -p $(DEBIAN_PACKAGING_BUILD_OUTPUT_DIR)
242243
find packaging/debian -mindepth 1 -maxdepth 1 -type f -name "*.in" -exec sh -c \
@@ -258,6 +259,15 @@ pre-build: | clean
258259

259260
build-termux-exec-main-app:
260261
@printf "\ntermux-exec-package: %s\n" "Building app/main"
262+
@mkdir -p $(BIN_BUILD_OUTPUT_DIR)
263+
264+
265+
@printf "\ntermux-exec-package: %s\n" "Building app/main/scripts/*"
266+
find app/main/scripts -type f -name "*.in" -exec sh -c \
267+
'sed $(TERMUX__CONSTANTS__SED_ARGS) "$$1" > $(BIN_BUILD_OUTPUT_DIR)/"$$(basename "$$1" | sed "s/\.in$$//")"' sh "{}" \;
268+
find $(BIN_BUILD_OUTPUT_DIR) -maxdepth 1 -exec chmod 700 "{}" \;
269+
find app/main/scripts -type l -exec cp -a "{}" $(BIN_BUILD_OUTPUT_DIR)/ \;
270+
261271

262272
build-libtermux-exec_nos_c_tre:
263273
@printf "\ntermux-exec-package: %s\n" "Building lib/termux-exec_nos_c_tre"
@@ -307,6 +317,10 @@ build-libtermux-exec-direct-ld-preload:
307317
@# primary library variant exported in `$LD_PRELOAD` by copying it
308318
@# to `libtermux-exec-ld-preload.so`.
309319
@# Creating a symlink may have performance impacts.
320+
@# The `postinst` script run during package installation runs
321+
@# `termux-exec-ld-preload-lib setup` to set the correct variant
322+
@# as per the execution type required for the Termux environment
323+
@# of the host device by running.
310324
cp -a $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec-direct-ld-preload.so $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec-ld-preload.so
311325

312326
@# For backward compatibility, symlink `libtermux-exec.so` to
@@ -317,18 +331,39 @@ build-libtermux-exec-direct-ld-preload:
317331
rm -f $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec.so
318332
ln -s libtermux-exec-ld-preload.so $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec.so
319333

334+
build-libtermux-exec-linker-ld-preload:
335+
@mkdir -p $(LIB_BUILD_OUTPUT_DIR)
336+
337+
@# Unlike `libtermux-exec_nos_c_tre.so` and `libtermux-exec_nos_c_tre.a`, all
338+
@# symbols are hidden, except the exported functions with
339+
@# `default` visibility with `__attribute__((visibility("default")))`,
340+
@# defined in the `TermuxExecLinkerLDPreloadEntryPoint.c` file meant to
341+
@# be intercepted by `$LD_PRELOAD`.
342+
@# `nm --demangle --dynamic --defined-only --extern-only /home/builder/.termux-build/termux-exec/src/build/output/usr/lib/libtermux-exec-linker-ld-preload.so`
343+
@printf "\ntermux-exec-package: %s\n" "Building lib/libtermux-exec-linker-ld-preload"
344+
$(CC) $(CFLAGS) $(LIBTERMUX_EXEC__NOS__C__CPPFLAGS) \
345+
-L$(LIB_BUILD_OUTPUT_DIR) $(LDFLAGS) -Wl,--exclude-libs=ALL \
346+
$(TERMUX__CONSTANTS__MACRO_FLAGS) \
347+
-fPIC -shared -fvisibility=hidden \
348+
-o $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec-linker-ld-preload.so \
349+
app/termux-exec-linker-ld-preload/src/termux/api/termux_exec/ld_preload/linker/TermuxExecLinkerLDPreloadEntryPoint.c \
350+
-l:libtermux-exec_nos_c_tre.a -l:libtermux-core_nos_c_tre.a
351+
320352

321353

322354
clean:
323355
rm -rf $(BUILD_OUTPUT_DIR)
324356

325357
install:
326358
@printf "termux-exec-package: %s\n" "Installing termux-exec-package in $(TERMUX_EXEC_PKG__INSTALL_PREFIX)"
359+
install -d $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/bin
327360
install -d $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/include
328361
install -d $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib
329362
install -d $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/libexec
330363

331364

365+
find $(BIN_BUILD_OUTPUT_DIR) -maxdepth 1 \( -type f -o -type l \) -exec cp -a "{}" $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/bin/ \;
366+
332367
rm -rf $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/include/termux-exec
333368
install -d $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/include/termux-exec/termux
334369

@@ -338,6 +373,7 @@ install:
338373

339374
install $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec-ld-preload.so $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec-ld-preload.so
340375
install $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec-direct-ld-preload.so $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec-direct-ld-preload.so
376+
install $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec-linker-ld-preload.so $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec-linker-ld-preload.so
341377
@# Use `cp` for symlink as `install` will copy the target regular file instead.
342378
cp -a $(LIB_BUILD_OUTPUT_DIR)/libtermux-exec.so $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec.so
343379

@@ -350,6 +386,9 @@ install:
350386
uninstall:
351387
@printf "termux-exec-package: %s\n" "Uninstalling termux-exec-package from $(TERMUX_EXEC_PKG__INSTALL_PREFIX)"
352388

389+
find app/main/scripts \( -type f -o -type l \) -exec sh -c \
390+
'rm -f $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/bin/"$$(basename "$$1" | sed "s/\.in$$//")"' sh "{}" \;
391+
353392
rm -rf $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/include/termux-exec
354393

355394

@@ -358,6 +397,7 @@ uninstall:
358397

359398
rm -f $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec-ld-preload.so
360399
rm -f $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec-direct-ld-preload.so
400+
rm -f $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec-linker-ld-preload.so
361401
rm -f $(TERMUX_EXEC_PKG__INSTALL_PREFIX)/lib/libtermux-exec.so
362402

363403
@printf "\ntermux-exec-package: %s\n\n" "Uninstall termux-exec-package successful"
@@ -382,4 +422,4 @@ check:
382422

383423

384424

385-
.PHONY: all pre-build build-termux-exec-main-app build-libtermux-exec_nos_c_tre build-libtermux-exec-direct-ld-preload clean install uninstall packaging-debian-build format check
425+
.PHONY: all pre-build build-termux-exec-main-app build-libtermux-exec_nos_c_tre build-libtermux-exec-direct-ld-preload build-libtermux-exec-linker-ld-preload clean install uninstall packaging-debian-build format check
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#!@TERMUX__PREFIX@/bin/sh
2+
# shellcheck shell=sh
3+
# shellcheck disable=SC2039,SC2059,SC3043
4+
5+
termux_exec__ld_preload_lib__init() {
6+
7+
TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL___N="@TERMUX_ENV__S_TERMUX_EXEC@LD_PRELOAD_LIB__LOG_LEVEL"
8+
termux_exec__ld_preload_lib__copy_variable TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL "$TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL___N" || return $?
9+
case "${TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL:-}" in
10+
0|1|2) :;; *) TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL=1;; # Default: `1` (OFF=0, NORMAL=1, DEBUG=2)
11+
esac
12+
13+
TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL___N="@TERMUX_ENV__S_TERMUX_EXEC@SYSTEM_LINKER_EXEC__LOG_LEVEL"
14+
15+
TERMUX__PREFIX___N="@TERMUX_ENV__S_TERMUX@PREFIX"
16+
termux_exec__ld_preload_lib__copy_variable TERMUX__PREFIX "$TERMUX__PREFIX___N" || return $?
17+
case "${TERMUX__PREFIX:-}" in
18+
/*[!/]) :;; *) TERMUX__PREFIX="@TERMUX__PREFIX@";;
19+
esac
20+
21+
}
22+
23+
24+
25+
termux_exec__ld_preload_lib__log() { local log_level="${1}"; shift; if [ "$TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL" -ge "$log_level" ]; then echo "@TERMUX__LNAME@-exec:" "$@"; fi }
26+
termux_exec__ld_preload_lib__log_error() { echo "@TERMUX__LNAME@-exec:" "$@" 1>&2; }
27+
termux_exec__ld_preload_lib__log_error_for_level() { local log_level="${1}"; shift; if [ "$TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL" -ge "$log_level" ]; then echo "@TERMUX__LNAME@-exec:" "$@" 1>&2; fi }
28+
29+
30+
31+
##
32+
# `termux_exec__ld_preload_lib__main` [`<argument...>`]
33+
##
34+
termux_exec__ld_preload_lib__main() {
35+
36+
termux_exec__ld_preload_lib__init || return $?
37+
38+
39+
if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
40+
termux_exec__ld_preload_lib__show_help || return $?
41+
return 0
42+
elif [ "${1:-}" = "--version" ]; then
43+
echo "@TERMUX_EXEC_PKG__VERSION@" || return $?
44+
return 0
45+
fi
46+
47+
48+
local command_type="${1:-}"
49+
[ $# -gt 0 ] && shift 1
50+
51+
if [ "$command_type" = "setup" ]; then
52+
if [ "${1:-}" = "-q" ] || [ "${1:-}" = "--quiet" ]; then
53+
TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL=0
54+
shift 1
55+
elif [ "${1:-}" = "-v" ]; then
56+
TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL=2
57+
shift 1
58+
fi
59+
else
60+
echo "The command '$command_type' passed to 'termux-exec-ld-preload-lib' is not valid." 1>&2
61+
return 64 # EX__USAGE
62+
fi
63+
64+
65+
termux_exec__ld_preload_lib__set_variable "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL___N" "$TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL" || return $?
66+
export "${TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL___N?}" || return $?
67+
68+
69+
if [ "$command_type" = "setup" ]; then
70+
termux_exec__ld_preload_lib__setup__run_command setup || return $?
71+
fi
72+
73+
return 0
74+
75+
}
76+
77+
78+
79+
##
80+
# `termux_exec__ld_preload_lib__setup__run_command`
81+
##
82+
termux_exec__ld_preload_lib__setup__run_command() {
83+
84+
local system_linker_exec_enabled
85+
86+
system_linker_exec_enabled="$(termux-exec-system-linker-exec is-enabled)" || return $?
87+
88+
local ld_preload_file
89+
90+
if [ "$system_linker_exec_enabled" != "true" ]; then
91+
ld_preload_file="$TERMUX__PREFIX/lib/libtermux-exec-direct-ld-preload.so"
92+
else
93+
ld_preload_file="$TERMUX__PREFIX/lib/libtermux-exec-linker-ld-preload.so"
94+
fi
95+
termux_exec__ld_preload_lib__log 1 "Setting primary Termux '\$LD_PRELOAD' library in 'libtermux-exec-ld-preload.so' to '$ld_preload_file'"
96+
97+
mkdir -p "$TERMUX__PREFIX/lib" || return $?
98+
99+
# Prevent `Segmentation fault (SIGSEGV fault addr)` when running
100+
# commands in calling shell of the script after new file has been
101+
# copied below.
102+
rm -f "$TERMUX__PREFIX/lib/libtermux-exec-ld-preload.so" || return $?
103+
104+
# Prevent `CANNOT LINK EXECUTABLE "cp": library "/data/data/com.termux/files/usr/lib/libtermux-exec-ld-preload.so" not found: needed by main executable`
105+
unset LD_PRELOAD || return $?
106+
107+
cp -a "$ld_preload_file" "$TERMUX__PREFIX/lib/libtermux-exec-ld-preload.so" || return $?
108+
109+
}
110+
111+
112+
113+
##
114+
# `termux_exec__ld_preload_lib__is_valid_shell_name` `<name>`
115+
##
116+
termux_exec__ld_preload_lib__is_valid_shell_name() {
117+
118+
if [ -z "${1:-}" ]; then
119+
return 1
120+
fi
121+
122+
local name_rest="${1#?}" # 1:end
123+
local name_first_char="${1%"$name_rest"}" # 0:1
124+
case "$name_first_char" in
125+
[a-zA-Z_])
126+
case "$name_rest" in
127+
*[!a-zA-Z0-9_]*) return 1;;
128+
*) return 0;;
129+
esac;;
130+
*) return 1;;
131+
esac
132+
133+
}
134+
135+
##
136+
# `termux_exec__ld_preload_lib__set_variable` `<variable_name>` `<variable_value>`
137+
##
138+
termux_exec__ld_preload_lib__set_variable() {
139+
140+
local variable_name="${1:-}"
141+
local variable_value="${2:-}"
142+
143+
if ! termux_exec__ld_preload_lib__is_valid_shell_name "$variable_name"; then
144+
termux_exec__ld_preload_lib__log_error "The variable_name '$variable_name' is not a valid shell variable name."
145+
return 64 # EX__USAGE
146+
fi
147+
148+
eval "$variable_name"=\"\$variable_value\"
149+
150+
}
151+
152+
termux_exec__ld_preload_lib__copy_variable() {
153+
154+
local output_variable_name="${1:-}"
155+
local input_variable_name="${2:-}"
156+
157+
if ! termux_exec__ld_preload_lib__is_valid_shell_name "$output_variable_name"; then
158+
termux_exec__ld_preload_lib__log_error "The output_variable_name '$output_variable_name' is not a valid shell variable name."
159+
return 1
160+
fi
161+
162+
if ! termux_exec__ld_preload_lib__is_valid_shell_name "$input_variable_name"; then
163+
termux_exec__ld_preload_lib__log_error "The input_variable_name '$input_variable_name' is not a valid shell variable name."
164+
return 1
165+
fi
166+
167+
eval "$output_variable_name"=\"\$\{"$input_variable_name":-\}\"
168+
169+
}
170+
171+
172+
173+
##
174+
# `termux_exec__ld_preload_lib__show_help`
175+
##
176+
termux_exec__ld_preload_lib__show_help() {
177+
178+
cat <<'HELP_EOF'
179+
termux-exec-ld-preload-lib can be used to manage Termux '$LD_PRELOAD'
180+
library.
181+
182+
183+
Usage:
184+
termux-exec-ld-preload-lib [command_options] <command>
185+
186+
Available commands:
187+
setup Setup the primary Termux '$LD_PRELOAD'
188+
library in 'libtermux-exec-ld-preload.so'
189+
to direct or linker variant.
190+
191+
Available command_options:
192+
[ -h | --help ] Display this help screen.
193+
[ --version ] Display version.
194+
[ -q | --quiet ] Set log level to 'OFF'.
195+
[ -v ]
196+
Set log level to 'DEBUG'.
197+
HELP_EOF
198+
199+
}
200+
201+
202+
203+
termux_exec__ld_preload_lib__main "$@"

0 commit comments

Comments
 (0)