diff --git a/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-ld-preload-lib.in b/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-ld-preload-lib.in index 6742a1c..98e7268 100644 --- a/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-ld-preload-lib.in +++ b/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-ld-preload-lib.in @@ -18,12 +18,16 @@ case "${TERMUX__PREFIX:-}" in /*[!/]) :;; *) TERMUX__PREFIX="@TERMUX__PREFIX@";; esac +TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE___N="@TERMUX_ENV__S_TERMUX_EXEC@SYSTEM_LINKER_EXEC__MODE" +termux_exec__ld_preload_lib__copy_variable TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE___N" || return $? + } -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 } +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.ld_preload_lib:" "$@"; fi } termux_exec__ld_preload_lib__log_error() { echo "@TERMUX__LNAME@-exec:" "$@" 1>&2; } +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.ld_preload_lib:" "$@" 1>&2; fi } @@ -80,13 +84,99 @@ termux_exec__ld_preload_lib__main() { ## termux_exec__ld_preload_lib__setup__run_command() { - local system_linker_exec_enabled + local return_value + + # Setting of primary Termux `$LD_PRELOAD` library must be done from + # perspective of it being loaded from inside a normal Termux owned + # shell running inside the Termux app. + # It must not be done from the perspective of root user, as the + # library file written would be owned by root user instead of + # Termux app uid. Similar restrictions are added in Termux apt/dpkg. + # Moreover, if the su/shell user is used to drop + # privileges/capabilities and uid to an unprivileged user, + # like to Termux uid, only the uid may be changed to + # Termux uid but the process context may not be switched + # to Termux app's normal context, like one of the + # `u:r:untrusted_app*` contexts, and so for the current process, + # `termux-exec-system-linker-exec should-enable` will wrongly + # assume `app_data_file_exec_exempted` as `true` if + # `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` is parsed as `enable`, + # and then `libtermux-exec-direct-ld-preload.so` would wrongly + # be set as the primary `$LD_PRELOAD` library instead of + # `libtermux-exec-linker-ld-preload.so`, where the direct variant + # may not have additional syscall hooks required for a fully + # functioning system linker exec environment. + # See also `termux_exec__system_linker_exec__should_enable__run_command()` + # in `termux-exec-system-linker-exec` and `shouldEnableSystemLinkerExec()` + # docs in `TermuxExecLDPreload.c`. + # This issue normally wouldn't occur if Termux app exports + # `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE=force` if app uses + # `targetSdkVersion` `>= 28` and when dropping privileges, + # `su --preserve-environment` is used or `termux-shell.env` is + # sourced in unprivileged shell. + # The user could also export `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` + # variable themselves with a custom value in a shell rc file, which + # would affect which library gets set during `termux-exec` package + # `postinst` script. The user could manually run the + # `termux-exec-ld-preload-lib` command as well, while exporting + # a custom variable value. + # If Termux packages are supposed to be run/updated from root in a + # specialized environment, then patches should be done to remove + # `uid = 0` check and only keep `u:r:runas_app:*` condition and + # remove other su contexts from case statement below. + + local uid + uid="$(id -u)" + return_value=$? + if [ $return_value -ne 0 ]; then + termux_exec__ld_preload_lib__log_error "Failed to get uid while setting primary Termux '\$LD_PRELOAD' library" + return $return_value + fi + + # Do not allow setting library as root (0) user. + # The shell (2000) user is still allowed, as packages may be getting + # set up for the `com.android.shell` package with the Termux rootfs + # under `/data/local/tmp` for adb usage. + if [ "$uid" = "0" ]; then + termux_exec__ld_preload_lib__log_error "Cannot set primary Termux '\$LD_PRELOAD' library while running as root (0) user" + return 1 + fi + + local system_linker_exec_mode="${TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE:-}" + # The process context check is only done by + # `termux_exec__system_linker_exec__should_enable__run_command()` + # if `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` is parsed as `enable`. + if [ "$system_linker_exec_mode" != "disable" ] && + [ "$system_linker_exec_mode" != "force" ] && [ "$system_linker_exec_mode" != "force_all" ]; then + local se_process_context + if [ "$TERMUX_EXEC__LD_PRELOAD_LIB__LOG_LEVEL" -ge 2 ]; then + se_process_context="$(cat "/proc/self/attr/current")" || true + else + se_process_context="$(cat "/proc/self/attr/current" 2>/dev/null)" || true + fi + if [ -n "$se_process_context" ]; then + termux_exec__ld_preload_lib__log_error_for_level 2 "se_process_context_from_file: '$se_process_context'" + case "$se_process_context" in + "u:r:runas_app:"*|"u:r:su:s0"|"u:r:ksu:s0"|"u:r:magisk:s0") + termux_exec__ld_preload_lib__log_error "Cannot set primary Termux '\$LD_PRELOAD' library as su/shell user \ +was used to drop privileges/capabilities and uid to an unprivileged user '$uid', \ +but the process context '$se_process_context' was not switched to Termux app's normal context" + termux_exec__ld_preload_lib__log_error "If updating 'termux-exec' package, \ +then do it from a normal shell inside Termux app instead of from inside root or adb/run-as shells" + return 1 + ;; + esac + fi + fi + + + local system_linker_exec_should_enable + system_linker_exec_should_enable="$(termux-exec-system-linker-exec should-enable)" || return $? - system_linker_exec_enabled="$(termux-exec-system-linker-exec is-enabled)" || return $? local ld_preload_file - if [ "$system_linker_exec_enabled" != "true" ]; then + if [ "$system_linker_exec_should_enable" != "true" ]; then ld_preload_file="$TERMUX__PREFIX/lib/libtermux-exec-direct-ld-preload.so" else ld_preload_file="$TERMUX__PREFIX/lib/libtermux-exec-linker-ld-preload.so" diff --git a/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-system-linker-exec.in b/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-system-linker-exec.in index 4c0d446..89822fa 100644 --- a/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-system-linker-exec.in +++ b/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-system-linker-exec.in @@ -10,12 +10,26 @@ case "${TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL:-}" in 0|1|2) :;; *) TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL=1;; # Default: `1` (OFF=0, NORMAL=1, DEBUG=2) esac +TERMUX__PREFIX___N="@TERMUX_ENV__S_TERMUX@PREFIX" +termux_exec__system_linker_exec__copy_variable TERMUX__PREFIX "$TERMUX__PREFIX___N" || return $? +case "${TERMUX__PREFIX:-}" in + /*[!/]) :;; *) TERMUX__PREFIX="@TERMUX__PREFIX@";; +esac + +TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE___N="@TERMUX_ENV__S_TERMUX_EXEC@SYSTEM_LINKER_EXEC__MODE" +termux_exec__system_linker_exec__copy_variable TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE___N" || return $? + } -termux_exec__system_linker_exec__log() { local log_level="${1}"; shift; if [ "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL" -ge "$log_level" ]; then echo "@TERMUX__LNAME@-exec:" "$@"; fi } +# Note that commands output result to stdout and so must not log any +# non-command-output to stdout and only to stderr. +# Use `termux_exec__system_linker_exec__log_error_for_level` for logs +# instead of `termux_exec__system_linker_exec__log` unless intended. +#termux_exec__system_linker_exec__log() { local log_level="${1}"; shift; if [ "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL" -ge "$log_level" ]; then echo "@TERMUX__LNAME@-exec.system_linker_exec:" "$@"; fi } termux_exec__system_linker_exec__log_error() { echo "@TERMUX__LNAME@-exec:" "$@" 1>&2; } +termux_exec__system_linker_exec__log_error_for_level() { local log_level="${1}"; shift; if [ "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL" -ge "$log_level" ]; then echo "@TERMUX__LNAME@-exec.system_linker_exec:" "$@" 1>&2; fi } @@ -39,7 +53,7 @@ termux_exec__system_linker_exec__main() { local command_type="${1:-}" [ $# -gt 0 ] && shift 1 - if [ "$command_type" = "is-enabled" ]; then + if [ "$command_type" = "is-enabled" ] || [ "$command_type" = "should-enable" ]; then if [ "${1:-}" = "-q" ] || [ "${1:-}" = "--quiet" ]; then TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL=0 shift 1 @@ -57,7 +71,9 @@ termux_exec__system_linker_exec__main() { # TODO: Add `should-enable-for-file` command. if [ "$command_type" = "is-enabled" ]; then - termux_exec__system_linker_exec__enabled__run_command output || return $? + termux_exec__system_linker_exec__is_enabled__run_command output || return $? + elif [ "$command_type" = "should-enable" ]; then + termux_exec__system_linker_exec__should_enable__run_command output || return $? fi if [ -n "$output" ]; then @@ -70,19 +86,105 @@ termux_exec__system_linker_exec__main() { +## +# `termux_exec__system_linker_exec__is_enabled__run_command` `` +## +termux_exec__system_linker_exec__is_enabled__run_command() { + + local return_value + + local output_variable_name="${1:-}" + + termux_exec__system_linker_exec__set_variable "$output_variable_name" "" || return $? + + + local android_build_version_sdk="${ANDROID__BUILD_VERSION_SDK:-}" + case "$android_build_version_sdk" in + ''|*[!0-9]*) + android_build_version_sdk="$(getprop "ro.build.version.sdk")" || true + case "$android_build_version_sdk" in + ''|*[!0-9]*) + termux_exec__system_linker_exec__log_error "Failed to get android_build_version_sdk value from 'getprop': '$android_build_version_sdk'" + return 1 + ;; + esac + ;; + esac + termux_exec__system_linker_exec__log_error_for_level 2 "android_build_version_sdk: '$android_build_version_sdk'" + + + local __system_linker_exec_is_enabled="false" + + # If running on Android `>= 10`. + # Android 5/6 would also require `LD_LIBRARY_PATH` to be set when + # executing a Termux binary, so this check would skip that. + # Note the `/system/bin/stat` command is not available on + # Android `5`, and only on Android `>= 6`, not that we execute it. + if [ "$android_build_version_sdk" -ge 29 ]; then + # We execute `$TERMUX__PREFIX/bin/stat` instead of `stat` + # so that execution explicitly happens for a file under Termux + # app data directory file (`app_data_file` context), + # and system linker execution is enabled by + # `shouldEnableSystemLinkerExecForFile()` function in `TermuxExecLDPreload.c`, + # since if only `stat` is executed, and `$PATH` is set to + # `/system/bin`, then `/system/bin/stat` would get executed + # instead, for which system linker exec will not be enabled and + # will result in a false negative. + # We pass `/proc/self/exe` instead of `/proc/$$/exe` so that `stat` + # reads its own exe path instead of that of current shell, which + # may not have linker as its exe, like exe would be set to + # `/system/bin/sh` if running inside a `/system/bin/sh` shell. + # We do not execute `readlink`/`realpath` as that may be + # patched by `libtermux-exec-ld-preload.so` to + # replace the `/proc/self/exe` path with value exported in + # `TERMUX_EXEC__PROC_SELF_EXE`. + local stat_output + stat_output="$("$TERMUX__PREFIX/bin/stat" -c "%N" /proc/self/exe)" + return_value=$? + if [ $return_value -ne 0 ]; then + termux_exec__system_linker_exec__log_error "Failed to get symlink path for '/proc/self/exe' with stat" + return $return_value + fi + termux_exec__system_linker_exec__log_error_for_level 2 "stat_output: \`$stat_output\`" + + # `stat` will output in the format: `'' -> ''` + local stat_prefix="'/proc/self/exe' -> " + case "$stat_output" in + "$stat_prefix"*) + stat_output="${stat_output#"$stat_prefix"}" # Remove prefix. + case "$stat_output" in + "'/apex/com.android.runtime/bin/linker64'"|"'/system/bin/linker64'"|"'/apex/com.android.runtime/bin/linker'"|"'/system/bin/linker'") + __system_linker_exec_is_enabled="true" + ;; + esac + ;; + esac + fi + + termux_exec__system_linker_exec__log_error_for_level 2 "system_linker_exec_is_enabled: '$__system_linker_exec_is_enabled'" + + termux_exec__system_linker_exec__set_variable "$output_variable_name" "$__system_linker_exec_is_enabled" + +} + + + ## # **IMPORTANT** The logic must be kept consistent with the -# `isSystemLinkerExecEnabled()` function in `TermuxExecLDPreload.c`. +# `shouldEnableSystemLinkerExec()` function in `TermuxExecLDPreload.c`. # # -# `termux_exec__system_linker_exec__enabled__run_command` `` +# `termux_exec__system_linker_exec__should_enable__run_command` `` ## -termux_exec__system_linker_exec__enabled__run_command() { +termux_exec__system_linker_exec__should_enable__run_command() { + + local return_value local output_variable_name="${1:-}" termux_exec__system_linker_exec__set_variable "$output_variable_name" "" || return $? + local android_build_version_sdk="${ANDROID__BUILD_VERSION_SDK:-}" case "$android_build_version_sdk" in ''|*[!0-9]*) @@ -95,69 +197,105 @@ termux_exec__system_linker_exec__enabled__run_command() { esac ;; esac - termux_exec__system_linker_exec__log 2 "android_build_version_sdk: '$android_build_version_sdk'" + termux_exec__system_linker_exec__log_error_for_level 2 "android_build_version_sdk: '$android_build_version_sdk'" local system_linker_exec_mode="${TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE:-}" case "${system_linker_exec_mode:-}" in - disable|enable|force) :;; + disable|enable|force|force_all) :;; *) system_linker_exec_mode="enable";; esac - termux_exec__system_linker_exec__log 2 "system_linker_exec_mode: '$system_linker_exec_mode'" + termux_exec__system_linker_exec__log_error_for_level 2 "system_linker_exec_mode: '$system_linker_exec_mode'" - local __system_linker_exec_enabled="false" + local __system_linker_exec_should_enable="false" if [ "$system_linker_exec_mode" = "disable" ]; then - __system_linker_exec_enabled="false" + __system_linker_exec_should_enable="false" - elif [ "$system_linker_exec_mode" = "force" ]; then + elif [ "$system_linker_exec_mode" = "force" ] || [ "$system_linker_exec_mode" = "force_all" ]; then local system_linker_exec_available="false" # If running on Android `>= 10`. if [ "$android_build_version_sdk" -ge 29 ]; then system_linker_exec_available="true" fi - termux_exec__system_linker_exec__log 2 "system_linker_exec_available: '$system_linker_exec_available'" + termux_exec__system_linker_exec__log_error_for_level 2 "system_linker_exec_available: '$system_linker_exec_available'" if [ "$system_linker_exec_available" = "true" ]; then - __system_linker_exec_enabled="true" + if [ "$system_linker_exec_mode" = "force" ]; then + local uid + uid="$(id -u)" + return_value=$? + if [ $return_value -ne 0 ]; then + termux_exec__system_linker_exec__log_error "Failed to get uid" + return $return_value + fi + + if [ "$uid" = "0" ] || [ "$uid" = "2000" ]; then + termux_exec__system_linker_exec__log_error_for_level 2 "uid_to_exempt: '$uid'" + else + __system_linker_exec_should_enable="true" + fi + elif [ "$system_linker_exec_mode" = "force_all" ]; then + __system_linker_exec_should_enable="true" + fi fi else # If running on Android `>= 10`. if [ "$android_build_version_sdk" -ge 29 ]; then local app_data_file_exec_exempted="false" - # If '/proc/self/attr/current' is not readable, - # then SeLinux may not be supported on the device. - # Reading the file with `cat` may fail with `Illegal argument` - # error on such devices, even though `test -f` and `test -r` - # commands for the `access()` call succeed. - # `cat: /proc/self/attr/current: Illegal argument` - # - https://github.com/termux/termux-exec-package/issues/30 - local se_process_context - se_process_context="$(cat "/proc/self/attr/current")" || true - if [ -z "$se_process_context" ]; then - termux_exec__system_linker_exec__log_error "Failed to read se_process_context value from '/proc/self/attr/current': '$se_process_context'" - termux_exec__system_linker_exec__log 2 "se_process_context_available: 'false'" + + local uid + uid="$(id -u)" + return_value=$? + if [ $return_value -ne 0 ]; then + termux_exec__system_linker_exec__log_error "Failed to get uid" + return $return_value + fi + + # If root or shell user. + if [ "$uid" = "0" ] || [ "$uid" = "2000" ]; then + termux_exec__system_linker_exec__log_error_for_level 2 "uid_to_exempt: '$uid'" app_data_file_exec_exempted="true" else - termux_exec__system_linker_exec__log 2 "se_process_context_from_file: '$se_process_context'" - case "$se_process_context" in - "u:r:untrusted_app_25:"*|"u:r:untrusted_app_27:"*) - app_data_file_exec_exempted="true" - ;; - esac + # If '/proc/self/attr/current' is not readable, + # then SeLinux may not be supported on the device. + # Reading the file with `cat` may fail with `Illegal argument` + # error on such devices, even though `test -f` and `test -r` + # commands for the `access()` call succeed. + # `cat: /proc/self/attr/current: Illegal argument` + # - https://github.com/termux/termux-exec-package/issues/30 + local se_process_context + if [ "$TERMUX_EXEC__SYSTEM_LINKER_EXEC__LOG_LEVEL" -ge 2 ]; then + se_process_context="$(cat "/proc/self/attr/current")" || true + else + se_process_context="$(cat "/proc/self/attr/current" 2>/dev/null)" || true + fi + if [ -z "$se_process_context" ]; then + termux_exec__system_linker_exec__log_error "Failed to read se_process_context value from '/proc/self/attr/current': '$se_process_context'" + termux_exec__system_linker_exec__log_error_for_level 2 "se_process_context_available: 'false'" + app_data_file_exec_exempted="true" + else + termux_exec__system_linker_exec__log_error_for_level 2 "se_process_context_from_file: '$se_process_context'" + case "$se_process_context" in + "u:r:untrusted_app_25:"*|"u:r:untrusted_app_27:"*|"u:r:runas_app:"*|"u:r:su:s0"|"u:r:ksu:s0"|"u:r:magisk:s0"|"u:r:shell:s0") + app_data_file_exec_exempted="true" + ;; + esac + fi fi - termux_exec__system_linker_exec__log 2 "app_data_file_exec_exempted: '$app_data_file_exec_exempted'" + termux_exec__system_linker_exec__log_error_for_level 2 "app_data_file_exec_exempted: '$app_data_file_exec_exempted'" if [ "$app_data_file_exec_exempted" = "false" ]; then - __system_linker_exec_enabled="true" + __system_linker_exec_should_enable="true" fi fi fi - termux_exec__system_linker_exec__log 2 "system_linker_exec_enabled: '$__system_linker_exec_enabled'" - termux_exec__system_linker_exec__set_variable "$output_variable_name" "$__system_linker_exec_enabled" + termux_exec__system_linker_exec__log_error_for_level 2 "system_linker_exec_should_enable: '$__system_linker_exec_should_enable'" + + termux_exec__system_linker_exec__set_variable "$output_variable_name" "$__system_linker_exec_should_enable" } @@ -237,8 +375,16 @@ Usage: termux-exec-system-linker-exec [command_options] Available commands: - is-enabled Get whether 'system_linker_exec' - is enabled in Termux. + is-enabled Get whether 'system_linker_exec' is + currently enabled in Termux based on + current process environment if a + Termux app data file were to be + executed. + should-enable Get whether 'system_linker_exec' should + be enabled in Termux based on current + process environment regardless of if a + Termux app data file were to be + executed. Available command_options: [ -h | --help ] Display this help screen. @@ -246,6 +392,11 @@ Available command_options: [ -q | --quiet ] Set log level to 'OFF'. [ -v ] Set log level to 'DEBUG'. + +termux-exec-system-linker-exec will print 'true' to stdout if an +enabled system linker exec state is to be returned, otherwise 'false'. +The result code will be '0' for both cases, and non-zero if an error +occurred while finding the state. HELP_EOF } diff --git a/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h b/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h index 063fe90..15e3cb6 100644 --- a/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h +++ b/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h @@ -18,7 +18,7 @@ extern "C" { /** - * Whether usage of `system_linker_exec` is to be enabled, like to + * Whether usage of `system_linker_exec` should be enabled, like to * bypass app data file execute restrictions. * * A call is made to `termuxExec_systemLinkerExec_mode_get()` to @@ -31,34 +31,56 @@ extern "C" { * - `system_linker_exec` is required to bypass app data file execute * restrictions, i.e device is running on Android `>= 10`. * - Effective user does not equal root (`0`) and shell (`2000`) user (used for - * [`adb`](https://developer.android.com/tools/adb)). + * [`adb`](https://developer.android.com/tools/adb)), as exec + * restrictions do not apply for them. * - `TERMUX__SE_PROCESS_CONTEXT` or its fallback `/proc/self/attr/current` - * does not start with `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25` and - * `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27` for which restrictions + * does not start with + * `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25` (`u:r:untrusted_app_25:`), + * `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27` (`u:r:untrusted_app_27:`) or + * `PROCESS_CONTEXT_PREFIX__RUNAS_APP` (`u:r:runas_app:`), and does not equal + * `PROCESS_CONTEXT__AOSP_SU` (`u:r:su:s0`), + * `PROCESS_CONTEXT__KERNEL_SU` (`u:r:ksu:s0`), + * `PROCESS_CONTEXT__MAGISK_SU` (`u:r:magisk:s0`) or + * `PROCESS_CONTEXT__SHELL` (`u:r:shell:s0`), for which restrictions * are exempted. * * If `force` is set, then `system_linker_exec` should only be used if: * - `system_linker_exec` is supported, i.e device is running on Android `>= 10`. + * - Effective user does not equal root (`0`) and shell (`2000`) user (used for + * [`adb`](https://developer.android.com/tools/adb)), as exec + * restrictions do not apply for them. * This can be used if running in an untrusted app with `targetSdkVersion` `<= 28`. * + * If `force_all` is set, then `system_linker_exec` should only be used if: + * - `system_linker_exec` is supported, i.e device is running on Android `>= 10`. + * - Effective user is not checked like it is for `force` mode and can + * equal root (`0`) and shell (`2000`) user. + * This can be used if running in an untrusted app with `targetSdkVersion` `<= 28`. + * + * The Termux app should export `force` mode instead of `force_all` mode + * in `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` if using + * `targetSdkVersion` `> 28` so that system linker exec should be + * forcefully engaged. Exporting `force_all` is not recommended as + * users running root and shell commands will get a performance hit. + * * See also `shouldEnableSystemLinkerExecForFile()`. * * **IMPORTANT** The logic must be kept consistent with the - * `termux_exec__system_linker_exec__enabled__run_command()` function + * `termux_exec__system_linker_exec__should_enable__run_command()` function * in `termux-exec-system-linker-exec`. * * @return Returns `0` if `system_linker_exec` is to be enabled, `1` if * `system_linker_exec` should not be used, otherwise `-1` on failures. */ -int isSystemLinkerExecEnabled(); +int shouldEnableSystemLinkerExec(); /** * Whether to use `system_linker_exec` for an executable file, like to * bypass app data file execute restrictions. * - * A call is made to `isSystemLinkerExecEnabled()` to check if - * `system_linker_exec` is to be enabled. If its enabled, then - * `system_linker_exec` is only to be used if + * A call is made to `shouldEnableSystemLinkerExec()` to check + * if `system_linker_exec` should be enabled. If it should be enabled, + * then `system_linker_exec` is only used if * `isPathUnderTermuxAppDataDir()` returns `true` for the * `executablePath`. * @@ -73,7 +95,7 @@ int isSystemLinkerExecEnabled(); * `/data/data/com.android.shell` (and using `force` mode) or * compiling packages for `/system` directory. * - * See also `isSystemLinkerExecEnabled()`. + * See also `shouldEnableSystemLinkerExec()`. * * @param executablePath The **normalized** executable or interpreter * path that will actually be executed. diff --git a/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.h b/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.h index 8789f9d..af13b8e 100644 --- a/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.h +++ b/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.h @@ -76,7 +76,10 @@ static const int ENV_DEF_VAL__TERMUX_EXEC__EXECVE_CALL__INTERCEPT = 1; * Values: * - `disable` (0) - The `system_linker_exec` will be disabled. * - `enable` (1) - The `system_linker_exec` will be enabled but only if required. - * - `force` (2) - The `system_linker_exec` will be force enabled even if not required. + * - `force` (2) - The `system_linker_exec` will be force enabled even if not required + * and effective user id does not equal root (`0`) and shell (`2000`). + * - `force_all` (3) - The `system_linker_exec` will be force enabled even if not required, + * regardless of effective user id. */ #define ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE TERMUX_ENV__S_TERMUX_EXEC__SYSTEM_LINKER_EXEC "MODE" static const int ENV_DEF_VAL__TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE = 1; @@ -164,11 +167,11 @@ int termuxExec_execveCall_intercept_get(); /** * Returns the `termux-exec` config for `system_linker_exec` based on - * the `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC` env variable. + * the `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` env variable. * - * @return Return `0` if `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC` is set - * to `disable`, `1` if set to `enable`, `2` if set to `force`, - * otherwise defaults to `1` (`enable`). + * @return Return `0` if `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` + * is set to `disable`, `1` if set to `enable`, `2` if set to `force`, + * `3` if set to `force_all`, otherwise defaults to `1` (`enable`). */ int termuxExec_systemLinkerExec_mode_get(); diff --git a/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c b/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c index 47aaba6..cdacb16 100644 --- a/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c +++ b/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c @@ -24,13 +24,13 @@ static const char* LOG_TAG = "ld-preload"; -static int sSystemLinkerExecEnabled = -1; +static int sSystemLinkerExecShouldEnable = -1; -int isSystemLinkerExecEnabled() { - if (sSystemLinkerExecEnabled == 0 || sSystemLinkerExecEnabled == 1) { - return sSystemLinkerExecEnabled; +int shouldEnableSystemLinkerExec() { + if (sSystemLinkerExecShouldEnable == 0 || sSystemLinkerExecShouldEnable == 1) { + return sSystemLinkerExecShouldEnable; } bool isRunningTests = libtermux_exec__nos__c__getIsRunningTests(); @@ -40,11 +40,11 @@ int isSystemLinkerExecEnabled() { logErrorVVerbose(LOG_TAG, "system_linker_exec_mode: '%d'", systemLinkerExecMode); } - int systemLinkerExecEnabled = 1; + int systemLinkerExecShouldEnable = 1; if (systemLinkerExecMode == 0) { // disable - systemLinkerExecEnabled = 1; // disable + systemLinkerExecShouldEnable = 1; // disable - } else if (systemLinkerExecMode == 2) { // force + } else if (systemLinkerExecMode == 2 || systemLinkerExecMode == 3) { // force or force_all int androidBuildVersionSdk = android_buildVersionSdk_get(); if (!isRunningTests) { logErrorVVerbose(LOG_TAG, "android_build_version_sdk: '%d'", androidBuildVersionSdk); @@ -58,7 +58,16 @@ int isSystemLinkerExecEnabled() { } if (systemLinkerExecAvailable) { - systemLinkerExecEnabled = 0; // enable + if (systemLinkerExecMode == 2) { // force + uid_t uid = geteuid(); + if (uid == 0 || uid == 2000) { + logErrorVVerbose(LOG_TAG, "uid_to_exempt: '%d'", uid); + } else { + systemLinkerExecShouldEnable = 0; // enable + } + } else if (systemLinkerExecMode == 3) { // force_all + systemLinkerExecShouldEnable = 0; // enable + } } } else { // enable @@ -77,18 +86,39 @@ int isSystemLinkerExecEnabled() { if (androidBuildVersionSdk >= 29) { // If running as root or shell user, then the process will // be assigned a different process context like - // `PROCESS_CONTEXT__AOSP_SU`, - // `PROCESS_CONTEXT__MAGISK_SU` or - // `PROCESS_CONTEXT__SHELL`, which will not be the same - // as the one that's exported in + // `PROCESS_CONTEXT__AOSP_SU` (`u:r:su:s0`), + // `PROCESS_CONTEXT__KERNEL_SU` (`u:r:ksu:s0`), + // `PROCESS_CONTEXT__MAGISK_SU` (`u:r:magisk:s0`) or + // `PROCESS_CONTEXT__SHELL` (`u:r:shell:s0`), which will + // not be the same as the one that's exported in // `ENV__TERMUX__SE_PROCESS_CONTEXT`, so we need to check // effective uid equals `0` or `2000` instead. Moreover, // other su providers may have different contexts, so we - // cannot just check AOSP or MAGISK contexts. + // cannot just check AOSP, MAGISK or KERNEL SU contexts. // - https://man7.org/linux/man-pages/man2/getuid.2.html + // However, if the su/shell user is used to drop + // privileges/capabilities and uid to an unprivileged user, + // like to Termux uid, only the uid may be changed to + // Termux uid but the process context may not be switched + // to Termux app's normal context, like one of the + // `u:r:untrusted_app*` contexts, and so the process will + // not be exempted from system linker exec unless those + // different process contexts are also explicitly exempted, + // as uid check will not be enough. + // For example, for the `adb shell run-as com.termux` + // command, the process context is switched to + // `u:r:runas_app:*` and only uid is changed to Termux uid. + // The `runas_app` context also allows execution of + // `app_data_file`, even if app uses `targetSdkVersion` `>= 28` + // and normally launches with `u:r:untrusted_app:*` + // instead of `u:r:untrusted_app_25:*` and `u:r:untrusted_app_27:*`. + // - https://cs.android.com/android/platform/superproject/+/android-16.0.0_r1:system/core/run-as/run-as.cpp;l=241-244 + // - https://cs.android.com/android/platform/superproject/+/android-16.0.0_r1:system/sepolicy/private/runas_app.te;l=8 + // For `su` commands, the original root process context + // may be preserved. uid_t uid = geteuid(); if (uid == 0 || uid == 2000) { - logErrorVVerbose(LOG_TAG, "uid: '%d'", uid); + logErrorVVerbose(LOG_TAG, "uid_to_exempt: '%d'", uid); appDataFileExecExempted = true; } else { char seProcessContext[80]; @@ -109,8 +139,15 @@ int isSystemLinkerExecEnabled() { } if (getSeProcessContextSuccess) { - appDataFileExecExempted = stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25) || - stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27); + // Listed in order of likely higher use. + appDataFileExecExempted = + stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27) || + stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25) || + stringEquals(seProcessContext, PROCESS_CONTEXT__SHELL) || + stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__RUNAS_APP) || + stringEquals(seProcessContext, PROCESS_CONTEXT__MAGISK_SU) || + stringEquals(seProcessContext, PROCESS_CONTEXT__KERNEL_SU) || + stringEquals(seProcessContext, PROCESS_CONTEXT__AOSP_SU); } else { // If even '/proc/self/attr/current' is not accessible, // then SeLinux may not be supported on the device. @@ -124,23 +161,23 @@ int isSystemLinkerExecEnabled() { } if (!appDataFileExecExempted) { - systemLinkerExecEnabled = 0; // enable + systemLinkerExecShouldEnable = 0; // enable } } } - sSystemLinkerExecEnabled = systemLinkerExecEnabled; + sSystemLinkerExecShouldEnable = systemLinkerExecShouldEnable; if (!isRunningTests) { - logErrorVVerbose(LOG_TAG, "system_linker_exec_enabled: '%d'", - sSystemLinkerExecEnabled == 0 ? true : false); + logErrorVVerbose(LOG_TAG, "system_linker_exec_should_enable: '%d'", + sSystemLinkerExecShouldEnable == 0 ? true : false); } - return sSystemLinkerExecEnabled; + return sSystemLinkerExecShouldEnable; } int shouldEnableSystemLinkerExecForFile(const char *executablePath) { - int systemLinkerExecResult = isSystemLinkerExecEnabled(); + int systemLinkerExecResult = shouldEnableSystemLinkerExec(); // If error or disabled, then just return. if (systemLinkerExecResult != 0) { return systemLinkerExecResult; @@ -162,7 +199,7 @@ int shouldEnableSystemLinkerExecForFile(const char *executablePath) { bool shouldEnableSystemLinkerExec = isExecutableUnderTermuxAppDataDir == 0; if (!isRunningTests) { - logErrorVVerbose(LOG_TAG, "system_linker_exec_enabled_for_file: '%d'", + logErrorVVerbose(LOG_TAG, "system_linker_exec_should_enable_for_file: '%d'", shouldEnableSystemLinkerExec); } diff --git a/lib/termux-exec_nos_c/tre/src/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.c b/lib/termux-exec_nos_c/tre/src/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.c index 04a9543..dd83579 100644 --- a/lib/termux-exec_nos_c/tre/src/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.c +++ b/lib/termux-exec_nos_c/tre/src/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.c @@ -42,6 +42,8 @@ int termuxExec_systemLinkerExec_mode_get() { return 1; } else if (strcmp(value, "force") == 0) { return 2; + } else if (strcmp(value, "force_all") == 0) { + return 3; } return def; } diff --git a/packaging/debian/postinst.in b/packaging/debian/postinst.in index bfbd259..daddcc3 100644 --- a/packaging/debian/postinst.in +++ b/packaging/debian/postinst.in @@ -10,16 +10,14 @@ log_error() { echo "termux-exec.postinst:" "$@" 1>&2; } ## main() { - log "Start" - # Run after the package is installed: `postinst configure ` # - https://manpages.debian.org/testing/dpkg-dev/deb-postinst.5.en.html#postinst if [ "$1" = "configure" ]; then + log "Start" set_primary_termux_ld_preload_library || return $? + log "End" fi - log "End" - } set_primary_termux_ld_preload_library() { diff --git a/site/pages/en/projects/docs/technical/index.md b/site/pages/en/projects/docs/technical/index.md index 764e1d2..c53e241 100644 --- a/site/pages/en/projects/docs/technical/index.md +++ b/site/pages/en/projects/docs/technical/index.md @@ -9,16 +9,16 @@ page_ref: "@ARK_PROJECT__VARIANT@/termux/termux-exec-package/docs/@ARK_DOC__VERS The [`termux-exec`](https://github.com/termux/termux-exec-package) package provides utils and libraries for Termux exec. It also provides a shared library that is meant to be preloaded with [`$LD_PRELOAD`](https://man7.org/linux/man-pages/man8/ld.so.8.html) for proper functioning of the Termux execution environment. There are `2` variants of the `$LD_PRELOAD` library provided by `termux-exec-package`. -1. `libtermux-exec-direct-ld-preload.so` with [`TermuxExecDirectLDPreloadEntryPoint.c`](https://github.com/termux/termux-exec-package/blob/v2.4.0/app/termux-exec-direct-ld-preload/src/termux/api/termux_exec/service/ld_preload/direct/TermuxExecDirectLDPreloadEntryPoint.c) as entry point that is used for the `direct` execution type. -2. `libtermux-exec-linker-ld-preload.so` with [`TermuxExecLinkerLDPreloadEntryPoint.c.c`](https://github.com/termux/termux-exec-package/blob/v2.4.0/app/termux-exec-direct-ld-preload/src/termux/api/termux_exec/service/ld_preload/direct/TermuxExecDirectLDPreloadEntryPoint.c) as entry point that is used for the [`system_linker_exec`](#system-linker-exec-solution) execution type. +1. `libtermux-exec-direct-ld-preload.so` with [`TermuxExecDirectLDPreloadEntryPoint.c`](https://github.com/termux/termux-exec-package/blob/v2.6.0/app/termux-exec-direct-ld-preload/src/termux/api/termux_exec/service/ld_preload/direct/TermuxExecDirectLDPreloadEntryPoint.c) as entry point that is used for the `direct` execution type. +2. `libtermux-exec-linker-ld-preload.so` with [`TermuxExecLinkerLDPreloadEntryPoint.c.c`](https://github.com/termux/termux-exec-package/blob/v2.6.0/app/termux-exec-direct-ld-preload/src/termux/api/termux_exec/service/ld_preload/direct/TermuxExecDirectLDPreloadEntryPoint.c) as entry point that is used for the [`system_linker_exec`](#system-linker-exec-solution) execution type. -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`](https://github.com/termux/termux-tools/blob/v1.45.0/scripts/login.in#L42-L54) script. This is done by the [`postinst`](https://github.com/termux/termux-exec-package/blob/v2.4.0/packaging/debian/postinst.in) script run during package installation, which runs [`termux-exec-ld-preload-lib setup`](https://github.com/termux/termux-exec-package/blob/v2.4.0/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-ld-preload-lib.in) 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`](https://github.com/termux/termux-exec-package/blob/v2.4.0/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-system-linker-exec.in) to check if `system_linker_exec` is to be enabled. A symlink is not used for `libtermux-exec-ld-preload.so` for potential performance impacts. The `$LD_PRELOAD` variable is currently not exported by the Termux app, like for shell commands started for plugins, check [here](https://github.com/termux/termux-tasker#termux-environment) for more info. +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`](https://github.com/termux/termux-tools/blob/v1.45.0/scripts/login.in#L42-L54) script. This is done by the [`postinst`](https://github.com/termux/termux-exec-package/blob/v2.6.0/packaging/debian/postinst.in) script run during package installation, which runs [`termux-exec-ld-preload-lib setup`](https://github.com/termux/termux-exec-package/blob/v2.6.0/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-ld-preload-lib.in) 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 should-enable`](https://github.com/termux/termux-exec-package/blob/v2.6.0/app/main/scripts/termux/api/termux_exec/service/ld_preload/termux-exec-system-linker-exec.in) to check if `system_linker_exec` is to be enabled. A symlink is not used for `libtermux-exec-ld-preload.so` for potential performance impacts. The `$LD_PRELOAD` variable is currently not exported by the Termux app, like for shell commands started for plugins, check [here](https://github.com/termux/termux-tasker#termux-environment) for more info. Both variants intercept `exec()` family of functions and support `system_linker_exec` execution, but the `libtermux-exec-linker-ld-preload.so` is meant to intercept additional functions to solve other issues specific to `system_linker_exec` execution, without affecting performance for users using `direct` execution type. 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. For backward compatibility, a symlink from `libtermux-exec.so` to `libtermux-exec-ld-preload.so` is also created so that older clients do not break which have exported path to `libtermux-exec.so` in `$LD_PRELOAD` via `login` script of older versions of `termux-tools `package. -The following functions are intercepted by the `$LD_PRELOAD` library variants, which are internally implemented by [`libtermux-exec_nos_c_tre`](https://github.com/termux/termux-exec-package/tree/v2.4.0/lib/termux-exec_nos_c/tre) c library for the Android native operating system (`nos`) running in Termux runtime environment (`tre`). +The following functions are intercepted by the `$LD_PRELOAD` library variants, which are internally implemented by [`libtermux-exec_nos_c_tre`](https://github.com/termux/termux-exec-package/tree/v2.6.0/lib/termux-exec_nos_c/tre) c library for the Android native operating system (`nos`) running in Termux runtime environment (`tre`). - [`exec()`](#exec) @@ -36,7 +36,7 @@ Some older devices/ROM do not support setting `$LD_PRELOAD`. ([1](https://github The `exec()` family of functions are [declared in `unistd.h`](https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/include/unistd.h;l=92-100) and [implemented by `exec.cpp`](https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/bionic/exec.cpp) in android [`bionic`](https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/README.md) `libc` library. The `exec()` functions are wrappers around the [`execve()`](https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/SYSCALLS.TXT;l=68) system call listed in [`syscalls(2)`](https://man7.org/linux/man-pages/man2/syscalls.2.html) provided by the [android/linux kernel](https://cs.android.com/android/kernel/superproject/+/ebe69964:common/include/linux/syscalls.h;l=790), which can also be directly called with the [`syscall(2)`](https://man7.org/linux/man-pages/man2/syscall.2.html) library function [declared in `unistd.h`](https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/include/unistd.h;l=308). Note that there is also a `execve()` wrapper in `unistd.h` around the `execve()` system call. The `termux-exec` overrides the entire `exec()` family of functions, but will not override direct calls to the `execve()` system call via `syscall(2)`, which is usually not directly called by programs. -The Termux `$LD_PRELOAD` library implements the intercepts in [`ExecIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/exec/ExecIntercept.c) and [`ExecVariantsIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/exec/ExecVariantsIntercept.c). +The Termux `$LD_PRELOAD` library implements the intercepts in [`ExecIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/direct/exec/ExecIntercept.c) and [`ExecVariantsIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/direct/exec/ExecVariantsIntercept.c). **See Also:** @@ -103,7 +103,7 @@ Support in Android `linker` to execute files was added in Android `10`, so this - https://cs.android.com/android/_/android/platform/bionic/+/8f639a40966c630c64166d2657da3ee641303194 - https://cs.android.com/android/_/android/platform/bionic/+/refs/tags/android-10.0.0_r1:linker/linker_main.cpp -The Termux `$LD_PRELOAD` library implements enabling `system_linker_exec` via the `isSystemLinkerExecEnabled()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L20), [2](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L31)) and `shouldEnableSystemLinkerExecForFile()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L55), [2](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L2137)) in `TermuxExecLDPreload.h` and implemented by `TermuxExecLDPreload.c`, and called by [`ExecIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/exec/ExecIntercept.c#L216). +The Termux `$LD_PRELOAD` library implements enabling `system_linker_exec` via the `shouldEnableSystemLinkerExec()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L20), [2](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L31)) and `shouldEnableSystemLinkerExecForFile()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L61), [2](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L170)) in `TermuxExecLDPreload.h` and implemented by `TermuxExecLDPreload.c`, and called by [`ExecIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/direct/exec/ExecIntercept.c#L296). #### System Linker Exec Issues diff --git a/site/pages/en/projects/docs/usage/index.md b/site/pages/en/projects/docs/usage/index.md index 2a76ec4..c0a1ebc 100644 --- a/site/pages/en/projects/docs/usage/index.md +++ b/site/pages/en/projects/docs/usage/index.md @@ -223,7 +223,7 @@ Whether to use [System Linker Exec Solution](../technical.md#system-linker-exec- **Type:** `string` -**Commits:** [`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11) +**Commits:** [`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11), [`89422f43`](https://github.com/termux/termux-exec-package/commit/89422f43), [`f7450d01`](https://github.com/termux/termux-exec-package/commit/f7450d01) **Version:** [`>= 2.0.0`](https://github.com/termux/termux-exec-package/releases/tag/v2.0.0) @@ -235,26 +235,38 @@ Whether to use [System Linker Exec Solution](../technical.md#system-linker-exec- - `enable` - The `system_linker_exec` will be enabled but only if required. -- `force` - The `system_linker_exec` will be force enabled even if not required and is supported. +- `force` - The `system_linker_exec` will be force enabled even if not required and effective user id does not equal root (`0`) and shell (`2000`). + +- `force_all` - The `system_linker_exec` will be force enabled even if not required and is supported, regardless of effective user id. -This is implemented by `isSystemLinkerExecEnabled()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L20), [2](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L31)) and `shouldEnableSystemLinkerExecForFile()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L55), [2](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L2137)) in `TermuxExecLDPreload.h` and implemented by `TermuxExecLDPreload.c`, and called by [`ExecIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.4.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/exec/ExecIntercept.c#L216). +This is implemented by `shouldEnableSystemLinkerExec()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L20), [2](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L31)) and `shouldEnableSystemLinkerExecForFile()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.h#L61), [2](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/TermuxExecLDPreload.c#L170)) in `TermuxExecLDPreload.h` and implemented by `TermuxExecLDPreload.c`, and called by [`ExecIntercept.c`](https://github.com/termux/termux-exec-package/blob/v2.6.0/lib/termux-exec_nos_c/tre/src/termux/api/termux_exec/service/ld_preload/direct/exec/ExecIntercept.c#L296). If `disable` is set, then `system_linker_exec` will never be used and the default `direct` execution type will be used. If `enable` is set, then `system_linker_exec` will only be used if: - `system_linker_exec` is required to bypass [App Data File Execute Restrictions](../technical.md#app-data-file-execute-restrictions), i.e device is running on Android `>= 10`. -- Effective user does not equal root (`0`) and shell (`2000`) user (used for [`adb`](https://developer.android.com/tools/adb)). -- [`TERMUX__SE_PROCESS_CONTEXT`](#TERMUX__SE_PROCESS_CONTEXT) does not start with `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25` (`u:r:untrusted_app_25:`) and `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27` (`u:r:untrusted_app_27:`) for which restrictions are exempted. For more info on them, check [`SelinuxUtils.h`](https://github.com/termux/termux-core-package/blob/v0.4.0/lib/termux-core_nos_c/tre/include/termux/termux_core__nos__c/v1/unix/os/selinux/SelinuxUtils.h). +- Effective user does not equal root (`0`) and shell (`2000`) user (used for [`adb`](https://developer.android.com/tools/adb)), as exec restrictions do not apply for them. +- [`TERMUX__SE_PROCESS_CONTEXT`](#TERMUX__SE_PROCESS_CONTEXT) does not start with `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25` (`u:r:untrusted_app_25:`), `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27` (`u:r:untrusted_app_27:`) or `PROCESS_CONTEXT_PREFIX__RUNAS_APP` (`u:r:runas_app:`), and does not equal `PROCESS_CONTEXT__AOSP_SU` (`u:r:su:s0`), `PROCESS_CONTEXT__KERNEL_SU` (`u:r:ksu:s0`), `PROCESS_CONTEXT__MAGISK_SU` (`u:r:magisk:s0`) or `PROCESS_CONTEXT__SHELL` (`u:r:shell:s0`), for which restrictions are exempted. For more info on them, check [`SelinuxUtils.h`](https://github.com/termux/termux-core-package/blob/v0.4.0/lib/termux-core_nos_c/tre/include/termux/termux_core__nos__c/v1/unix/os/selinux/SelinuxUtils.h). - Executable or interpreter path is under [`TERMUX_APP__DATA_DIR`] or [`TERMUX_APP__LEGACY_DATA_DIR`] directory. If `force` is set, then `system_linker_exec` will only be used if: - `system_linker_exec` is supported, i.e device is running on Android `>= 10`. +- Effective user does not equal root (`0`) and shell (`2000`) user (used for [`adb`](https://developer.android.com/tools/adb)), as exec restrictions do not apply for them. +- Executable or interpreter path is under [`TERMUX_APP__DATA_DIR`] or [`TERMUX_APP__LEGACY_DATA_DIR`] directory. +This can be used if running in an untrusted app with `targetSdkVersion` `<= 28`. + +If `force_all` is set, then `system_linker_exec` will only be used if: +- `system_linker_exec` is supported, i.e device is running on Android `>= 10`. +- Effective user is not checked like it is for `force` mode and can equal root (`0`) and shell (`2000`) user. - Executable or interpreter path is under [`TERMUX_APP__DATA_DIR`] or [`TERMUX_APP__LEGACY_DATA_DIR`] directory. This can be used if running in an untrusted app with `targetSdkVersion` `<= 28`. The executable or interpreter paths are checked under [`TERMUX_APP__DATA_DIR`]/[`TERMUX_APP__LEGACY_DATA_DIR`] instead of `TERMUX__ROOTFS` as files could be executed from `TERMUX__APPS_DIR` and `TERMUX__CACHE_DIR`, which are not under the Termux rootfs. Additionally, Termux rootfs may not exist under app data directory at all and could be under another directory under Android rootfs `/`, like if compiling packages for `shell` user for the `com.android.shell` package with the Termux rootfs under `/data/local/tmp` instead of `/data/data/com.android.shell` (and using `force` mode) or compiling packages for `/system` directory. -To get whether `termux-exec` will use `system_linker_exec` at runtime, run the `termux-exec-system-linker-exec is-enabled` command. +The Termux app should export `force` mode instead of `force_all` mode in `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` if using `targetSdkVersion` `> 28` so that system linker exec should be forcefully engaged. Exporting `force_all` is not recommended as users running root and shell commands will get a performance hit. + +To get whether `system_linker_exec` is currently enabled in Termux based on current process environment if a Termux app data file were to be executed, run the `termux-exec-system-linker-exec is-enabled` command. +To get whether `system_linker_exec` should be enabled in Termux based on current process environment regardless of if a Termux app data file were to be executed, run the `termux-exec-system-linker-exec should-enable` command. ##   @@ -316,7 +328,7 @@ So `termux-exec` sets the `TERMUX_EXEC__PROC_SELF_EXE` env variable when `execve   -Note that if `termux-exec` is set in `LD_PRELOAD`, and it sets `TERMUX_EXEC__PROC_SELF_EXE` for the current process/shell, and then `LD_PRELOAD` is unset, then new processes after second nested `exec()` will get old and wrong value of `TERMUX_EXEC__PROC_SELF_EXE` belonging to the first nested process since `termux-exec` will not get called for the second nested process to set the updated value. The `termux-exec` will be called for the first nested process, because just unsetting `LD_PRELOAD` in current process will not unload the `termux-exec` library and it requires at least one nested `exec()`. The `termux-exec` library could unset `TERMUX_EXEC__PROC_SELF_EXE` if `LD_PRELOAD` isn't already set, but then if the first nested process is under [`TERMUX_APP__DATA_DIR`]/[`TERMUX_APP__LEGACY_DATA_DIR`], it will not have access to `TERMUX_EXEC__PROC_SELF_EXE` to read the actual value of the execution command. This would normally not be an issue if `LD_PRELOAD` being set to the `termux-exec` library is mandatory so that it can `system_linker_exec` commands if running with `targetSdkVersion` `>= 29` on an android `>= 10` device, as otherwise permission denied errors would trigger for any command under [`TERMUX_APP__DATA_DIR`]/[`TERMUX_APP__LEGACY_DATA_DIR`] anyways, unless user manually wraps second nested process with `/system/bin/linker64`. This will still be an issue if `system_linker_exec` is optional due to running with an older `targetSdkVersion` or on an older android device and `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` is set to `force`, since then `TERMUX_EXEC__PROC_SELF_EXE` would get exported and will be used by termux packages. +Note that if `termux-exec` is set in `LD_PRELOAD`, and it sets `TERMUX_EXEC__PROC_SELF_EXE` for the current process/shell, and then `LD_PRELOAD` is unset, then new processes after second nested `exec()` will get old and wrong value of `TERMUX_EXEC__PROC_SELF_EXE` belonging to the first nested process since `termux-exec` will not get called for the second nested process to set the updated value. The `termux-exec` will be called for the first nested process, because just unsetting `LD_PRELOAD` in current process will not unload the `termux-exec` library and it requires at least one nested `exec()`. The `termux-exec` library could unset `TERMUX_EXEC__PROC_SELF_EXE` if `LD_PRELOAD` isn't already set, but then if the first nested process is under [`TERMUX_APP__DATA_DIR`]/[`TERMUX_APP__LEGACY_DATA_DIR`], it will not have access to `TERMUX_EXEC__PROC_SELF_EXE` to read the actual value of the execution command. This would normally not be an issue if `LD_PRELOAD` being set to the `termux-exec` library is mandatory so that it can `system_linker_exec` commands if running with `targetSdkVersion` `>= 29` on an android `>= 10` device, as otherwise permission denied errors would trigger for any command under [`TERMUX_APP__DATA_DIR`]/[`TERMUX_APP__LEGACY_DATA_DIR`] anyways, unless user manually wraps second nested process with `/system/bin/linker64`. This will still be an issue if `system_linker_exec` is optional due to running with an older `targetSdkVersion` or on an older android device and `TERMUX_EXEC__SYSTEM_LINKER_EXEC__MODE` is set to `force`/`force_all`, since then `TERMUX_EXEC__PROC_SELF_EXE` would get exported and will be used by termux packages. **To prevent issues, if `LD_PRELOAD` is unset in current process, then `TERMUX_EXEC__PROC_SELF_EXE` must also be unset in the first nested process by the user themselves.** For example, running following will echo `/bin/sh` value twice instead of `/bin/sh` first and `/bin/dash` second if `LD_PRELOAD` were to be set. diff --git a/site/pages/en/projects/releases/2/v2.0.0.md b/site/pages/en/projects/releases/2/v2.0.0.md index 064cecf..bcd640a 100644 --- a/site/pages/en/projects/releases/2/v2.0.0.md +++ b/site/pages/en/projects/releases/2/v2.0.0.md @@ -30,7 +30,7 @@ page_ref: "@ARK_PROJECT__VARIANT@/termux/termux-exec-package/releases/2/v2.0.0.h - Add support to execute ELF files by passing them to `/system/bin/linker*` to bypass android app data file exec restriction if using `targetSdkVersion` `>= 28` on Android `>= 10`. Check [technical](https://github.com/termux/termux-exec-package/blob/master/site/pages/en/projects/docs/technical/index.md) and [system linker exec](https://github.com/agnostic-apollo/Android-Docs/blob/master/site/pages/en/projects/docs/apps/processes/app-data-file-execute-restrictions.md#system-linker-exec) docs for info on how `system_linker_exec` works and why it is needed. ([`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11)) - 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. ([`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11)) - Since when executing with linker, the `/proc/self/exe` will be set to linker path, export `TERMUX_EXEC__PROC_SELF_EXE` environment variable with actual path to executable being executed so that packages can be patched to read it instead. Additional hocking will need to be done for programs that read `/proc//exe`. ([`5ea25ee3`](https://github.com/termux/termux-exec-package/commit/5ea25ee3), [`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11)) -- 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 `isSystemLinkerExecEnabled()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.h#L20), [2](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/src/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.c#L31)) and `shouldEnableSystemLinkerExecForFile()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.h#L55), [2](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/src/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.c#L2137)) in `TermuxExecLDPreload.h` and implemented by `TermuxExecLDPreload.c` for more info and how its handled. 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`). ([`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11)) +- 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 `isSystemLinkerExecEnabled()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.h#L20), [2](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/src/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.c#L31)) and `shouldEnableSystemLinkerExecForFile()` function ([1](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/include/termux/termux_exec__nos__c/v1/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.h#L55), [2](https://github.com/termux/termux-exec-package/blob/v2.0.0/lib/termux-exec_nos_c_tre/src/termux/api/termux_exec/ld_preload/TermuxExecLDPreload.c#L137)) in `TermuxExecLDPreload.h` and implemented by `TermuxExecLDPreload.c` for more info and how its handled. 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`). ([`db738a11`](https://github.com/termux/termux-exec-package/commit/db738a11))