|
1 |
| -# termux-exec |
2 |
| -A `execve()` wrapper to fix two problems with exec-ing files in Termux. |
| 1 | +# termux-exec-package |
3 | 2 |
|
4 |
| -# Problem 1: Cannot execute files not part of the APK |
5 |
| -Android 10 started blocking executing files under the app data directory, as |
6 |
| -that is a [W^X](https://en.wikipedia.org/wiki/W%5EX) violation - files should be either |
7 |
| -writeable or executable, but not both. Resources: |
| 3 | +The [`termux-exec`](https://github.com/termux/termux-exec) package 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. |
8 | 4 |
|
9 |
| -- [Google Android issue](https://issuetracker.google.com/issues/128554619) |
10 |
| -- [Termux: No more exec from data folder on targetAPI >= Android Q](https://github.com/termux/termux-app/issues/1072) |
11 |
| -- [Termux: Revisit the Android W^X problem](https://github.com/termux/termux-app/issues/2155) |
| 5 | +### Contents |
12 | 6 |
|
13 |
| -While there is merit in that general principle, this prevents using Termux and Android |
14 |
| -as a general computing device, where it should be possible for users to create executable |
15 |
| -scripts and binaries. |
| 7 | +- [Project](#project) |
16 | 8 |
|
17 |
| -# Solution 1: Cannot execute files not part of the APK |
18 |
| -Create an `exec` interceptor using [LD_PRELOAD](https://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Unix-like_systems), |
19 |
| -that instead of executing an ELF file directly, executes `/system/bin/linker64 /path/to/elf`. |
20 |
| -Explanation follows below. |
| 9 | +--- |
21 | 10 |
|
22 |
| -On Linux, the kernel is normally responsible for loading both the executable and the |
23 |
| -[dynamic linker](https://en.wikipedia.org/wiki/Dynamic_linker). The executable is invoked |
24 |
| -by file path with the [execve system call](https://en.wikipedia.org/wiki/Exec_(system_call)). |
25 |
| -The kernel loads the executable into the process, and looks for a `PT_INTERP` entry in |
26 |
| -its [ELF program header table](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#Program_header) |
27 |
| -of the file - this specifies the path to the dynamic linker (`/system/bin/linker64` for 64-bit Android). |
| 11 | + |
28 | 12 |
|
29 |
| -There is another way to load the two ELF objects: |
30 |
| -[since 2018](https://android.googlesource.com/platform/bionic/+/8f639a40966c630c64166d2657da3ee641303194) |
31 |
| -the dynamic linker can be invoked directly with `exec`. |
32 |
| -If passed the filename of an executable, the dynamic linker will load and run the executable itself. |
33 |
| -So, instead of executing `path/to/mybinary`, it's possible to execute |
34 |
| -`/system/bin/linker64 /absolute/path/to/mybinary` (the linker needs an absolute path). |
35 | 13 |
|
36 |
| -This is what `termux-exec` does to circumvent the block on executing files in the data |
37 |
| -directory - the kernel sees only `/system/bin/linker64` being executed. |
38 | 14 |
|
39 |
| -This also means that we need to extract [shebangs](https://en.wikipedia.org/wiki/Shebang_(Unix)). So for example, a call to execute: |
40 | 15 |
|
41 |
| -```sh |
42 |
| -./path/to/myscript.sh <args> |
43 |
| -``` |
44 | 16 |
|
45 |
| -where the script has a `#!/path/to/interpreter` shebang, is replaced with: |
| 17 | +## Project |
46 | 18 |
|
47 |
| -```sh |
48 |
| -/system/bin/linker64 /path/to/interpreter ./path/to/myscript.sh <args> |
49 |
| -``` |
| 19 | +**Check the `termux-exec` project info [here](site/pages/en/projects/index.md), including `docs` and `releases` info.** |
50 | 20 |
|
51 |
| -Implications: |
| 21 | +--- |
52 | 22 |
|
53 |
| -- It's important that `LD_PRELOAD` is kept - see e.g. [this change in sshd](https://github.com/termux/termux-packages/pull/18069). |
54 |
| -We could also consider patching this exec interception into the build process of termux packages, so `LD_PRELOAD` would not be necessary for packages built by the termux-packages repository. |
55 |
| - |
56 |
| -- The executable will be `/system/bin/linker64`. So some programs that inspects the executable name (on itself or other programs) using `/proc/${PID}/exec` or `/proc/${PID}/comm` (where `$(PID}` could be `self`, for the current process) needs to be changed to instead inspect `argv0` of the process instead. See [this llvm driver change](https://github.com/termux/termux-packages/pull/18074) and [this pgrep/pkill change](https://github.com/termux/termux-packages/pull/18075). |
57 |
| - |
58 |
| -- Statically linked binaries will not work. These are rare in Android and Termux, but zig currently produces statically linked binaries against musl libc. |
59 |
| - |
60 |
| -- The interception using `LD_PRELOAD` will only work for programs using the [C library wrappers](https://linux.die.net/man/3/execve) for executing a new process, not when using the `execve` system call directly. Luckily most programs do use this. Programs using raw system calls needs to be patched or be run under [proot](https://wiki.termux.com/wiki/PRoot). |
61 |
| - |
62 |
| -**NOTE**: The above example used `/system/bin/linker64` - on 32-bit systems, the corresponding |
63 |
| -path is `/system/bin/linker`. |
64 |
| - |
65 |
| -**NOTE**: While this circumvents the technical restriction, it still might be considered |
66 |
| -violating [Google Play policy](https://support.google.com/googleplay/android-developer/answer/9888379). |
67 |
| -So this workaround is not guaranteed to enable Play store distribution of Termux - but it's |
68 |
| -worth an attempt, and regardless of Play store distribution, updating the targetSdk is necessary. |
69 |
| - |
70 |
| -# Problem 2: Shebang paths |
71 |
| -A lot of Linux software is written with the assumption that `/bin/sh`, `/usr/bin/env` |
72 |
| -and similar file exists. This is not the case on Android where neither `/bin/` nor `/usr/` |
73 |
| -exists. |
74 |
| - |
75 |
| -When building packages for Termux those hard-coded assumptions are patched away - but this |
76 |
| -does not help with installing scripts and programs from other sources than Termux packages. |
77 |
| - |
78 |
| -# Solution 2: Shebang paths |
79 |
| -Create an `execve()` wrapper that rewrites calls to execute files under `/bin/` and `/usr/bin` |
80 |
| -into the matching Termux executables under `$PREFIX/bin/` and inject that into processes |
81 |
| -using `LD_PRELOAD`. |
82 |
| - |
83 |
| -# How to install |
84 |
| -1. Install with `pkg install termux-exec`. |
85 |
| -2. Exit your current session and start a new one. |
86 |
| -3. From now on shebangs such as `/bin/sh` and `/usr/bin/env python` should work. |
87 |
| - |
88 |
| -# Where is LD_PRELOAD set? |
89 |
| -The `$PREFIX/bin/login` program which is used to create new Termux sessions checks for |
90 |
| -`$PREFIX/lib/libtermux-exec.so` and if so sets up `LD_PRELOAD` before launching the login shell. |
91 |
| - |
92 |
| -Soon, when making a switch to target Android 10+, this will be setup by the Termux app even before |
93 |
| -launching any process, as `LD_PRELOAD` will be necessary for anything non-system to execute. |
| 23 | + |
0 commit comments