这是indexloc提供的服务,不要输入任何密码
Skip to content

Commit 9f26d30

Browse files
Added: Re-add system_linker_exec support initially added in 5ea25ee and removed in xxxxx
- `lib/termux-exec_c/src/termux/api/termux_exec/exec/ExecIntercept.c` from `libtermux-exec_c` handles the `system_linker_exec` now. - Added the `string` `TERMUX_EXEC__SYSTEM_LINKER_EXEC` environment variable for whether to use `system_linker_exec` if `TERMUX_EXEC__INTERCEPT_EXECVE` 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 `shouldSystemLinkerExec()` 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 `getAndroidBuildVersionSdk()` from `libtermux-core_c` 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 e1995a1 commit 9f26d30

File tree

4 files changed

+250
-4
lines changed

4 files changed

+250
-4
lines changed

lib/termux-exec_c/include/termux/termux_exec__c/v1/termux/api/termux_exec/exec/ExecIntercept.h

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,51 @@ int inspectFileHeader(const char *termuxPrefixDir, char *header, size_t headerLe
195195
struct FileHeaderInfo *info);
196196

197197

198+
/**
199+
* Whether to use `system_linker_exec`, like to bypass app data file
200+
* execute restrictions.
201+
*
202+
* A call is made to `getTermuxExecSystemLinkerExecConfig()` to
203+
* get the config for using `system_linker_exec`.
204+
*
205+
* If `disable` is set, then `system_linker_exec` should not be used
206+
* and the default `direct` execution type should be used.
207+
*
208+
* If `enable` is set, then `system_linker_exec` should only be used if:
209+
* - `system_linker_exec` is required to bypass app data file execute
210+
* restrictions, i.e device is running on Android `>= 10`.
211+
* - Effective user does not equal root (`0`) and shell (`2000`) user (used for
212+
* [`adb`](https://developer.android.com/tools/adb)).
213+
* - `TERMUX__SE_PROCESS_CONTEXT` or its fallback `/proc/self/attr/current`
214+
* does not start with `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25` and
215+
* `PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27` for which restrictions
216+
* are exempted.
217+
* - `isPathUnderTermuxAppDataDir()` returns `true` for the `executablePath`.
218+
*
219+
* If `force` is set, then `system_linker_exec` should only be used if:
220+
* - `system_linker_exec` is supported, i.e device is running on Android `>= 10`.
221+
* - `isPathUnderTermuxAppDataDir()` returns `true` for the `executablePath`.
222+
* This can be used if running in an untrusted app with `targetSdkVersion` `<= 28`.
223+
*
224+
* The executable or interpreter paths are checked under
225+
* `TERMUX_APP__DATA_DIR` or `TERMUX_APP__LEGACY_DATA_DIR` instead of
226+
* `TERMUX__ROOTFS` as files could be executed from `TERMUX__APPS_DIR`
227+
* and `TERMUX__CACHE_DIR`, which are not under the Termux rootfs.
228+
* Additionally, Termux rootfs may not exist under app data directory
229+
* at all and could be under another directory under Android rootfs `/`,
230+
* like if compiling packages for `shell` user for the `com.android.shell`
231+
* package with the Termux rootfs under `/data/local/tmp` instead of
232+
* `/data/data/com.android.shell` (and using `force` mode) or
233+
* compiling packages for `/system` directory.
234+
*
235+
* @param executablePath The **normalized** executable or interpreter
236+
* path that will actually be executed.
237+
* @return Returns `0` if `system_linker_exec` should not be used,
238+
* `1` if `system_linker_exec` should be used, otherwise `-1` on failures.
239+
*/
240+
int shouldSystemLinkerExec(const char *executablePath);
241+
242+
198243

199244
/**
200245
* Whether variables in `LD_VARS_TO_UNSET` should be unset before `exec()`
@@ -237,6 +282,9 @@ int modifyExecEnv(char *const *envp, char ***newEnvpPointer,
237282
* `FileHeaderInfo.origInterpreterPath`, otherwise the original
238283
* `argv[0]` passed to `execve()` will be preserved.
239284
*
285+
* If `systemLinkerExec` is `true`, then `argv[1]` will be set
286+
* to `executablePath` to be executed by the linker.
287+
*
240288
* If `interpreterSet` is set, then `FileHeaderInfo.interpreterArg`
241289
* will be appended if set, followed by the `origExecutablePath`
242290
* passed to `execve()`.
@@ -251,14 +299,15 @@ int modifyExecEnv(char *const *envp, char ***newEnvpPointer,
251299
* path that will actually be executed.
252300
* @param interpreterSet Whether a interpreter is set in the executable
253301
* file.
302+
* @param systemLinkerExec Whether `system_linker_exec` is enabled.
254303
* @param info The `FileHeaderInfo` for the executable file.
255304
* @return Returns `0` if successfully modified the args, otherwise
256305
* `-1` on failures. Its the callers responsibility to call `free()`
257306
* on the `newArgvPointer` passed.
258307
*/
259308
int modifyExecArgs(char *const *argv, const char ***newArgvPointer,
260309
const char *origExecutablePath, const char *executablePath,
261-
bool interpreterSet, struct FileHeaderInfo *info);
310+
bool interpreterSet, bool systemLinkerExec, struct FileHeaderInfo *info);
262311

263312

264313

lib/termux-exec_c/include/termux/termux_exec__c/v1/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,42 @@ extern "C" {
4444
#define ENV__TERMUX_EXEC__INTERCEPT_EXECVE TERMUX_ENV__S_TERMUX_EXEC "INTERCEPT_EXECVE"
4545
static const bool E_DEF_VAL__TERMUX_EXEC__INTERCEPT_EXECVE = true;
4646

47+
/**
48+
* Environment variable for whether use System Linker Exec Solution,
49+
* like to bypass App Data File Execute Restrictions.
50+
*
51+
* See also `shouldSystemLinkerExec()`
52+
*
53+
* Type: `string`
54+
* Default key: `TERMUX_EXEC__SYSTEM_LINKER_EXEC`
55+
* Default value: E_DEF_VAL__TERMUX_EXEC__SYSTEM_LINKER_EXEC
56+
* Values:
57+
* - `disable` - The `system_linker_exec` will be disabled.
58+
* - `enable` - The `system_linker_exec` will be enabled but only if required.
59+
* - `force` - The `system_linker_exec` will be force enabled even if not required.
60+
*/
61+
#define ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC TERMUX_ENV__S_TERMUX_EXEC "SYSTEM_LINKER_EXEC"
62+
static const int E_DEF_VAL__TERMUX_EXEC__SYSTEM_LINKER_EXEC = 1;
63+
64+
65+
66+
/**
67+
* Environment variable for the path to the executable file is being
68+
* executed by `execve()` is using `system_linker_exec`.
69+
*
70+
* Type: `string`
71+
* Default key: `TERMUX_EXEC__PROC_SELF_EXE`
72+
* Values:
73+
* - The normalized, absolutized and prefixed path for the executable
74+
* file is being executed by `execve()` if `system_linker_exec` is
75+
* being used.
76+
*/
77+
#define ENV__TERMUX_EXEC__PROC_SELF_EXE TERMUX_ENV__S_TERMUX_EXEC "PROC_SELF_EXE"
78+
#define ENV_PREFIX__TERMUX_EXEC__PROC_SELF_EXE ENV__TERMUX_EXEC__PROC_SELF_EXE "="
79+
80+
81+
82+
4783

4884
/**
4985
* Returns the `termux-exec` config for `Logger` log level
@@ -66,6 +102,19 @@ int getTermuxExecLogLevel();
66102
* bool enabled, `false` if bool disabled, otherwise defaults to `true`.
67103
*/
68104
bool isTermuxExecExecveInterceptEnabled();
105+
106+
/**
107+
* Returns the `termux-exec` config for `system_linker_exec` based on
108+
* the `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC` env variable.
109+
*
110+
* @return Return `0` if `ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC` is set
111+
* to `disable`, `1` if set to `enable`, `2` if set to `force`,
112+
* otherwise defaults to `1` (`enable`).
113+
*/
114+
int getTermuxExecSystemLinkerExecConfig();
115+
116+
117+
69118
#ifdef __cplusplus
70119
}
71120
#endif

lib/termux-exec_c/src/termux/api/termux_exec/exec/ExecIntercept.c

Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,15 @@ int execveInterceptInternal(const char *origExecutablePath, char *const argv[],
223223

224224

225225

226+
227+
// Check if `system_linker_exec` is required.
228+
int systemLinkerExec = shouldSystemLinkerExec(executablePath);
229+
if (systemLinkerExec < 0) {
230+
return -1;
231+
}
232+
233+
234+
226235
bool modifyEnv = false;
227236
bool unsetLdVarsFromEnv = shouldUnsetLDVarsFromEnv(info.isNonNativeElf, executablePath);
228237
logErrorVVerbose(LOG_TAG, "unset_ld_vars_from_env: '%d'", unsetLdVarsFromEnv);
@@ -231,6 +240,29 @@ int execveInterceptInternal(const char *origExecutablePath, char *const argv[],
231240
modifyEnv = true;
232241
}
233242

243+
244+
245+
// If `system_linker_exec` is going to be used, then set `TERMUX_EXEC__PROC_SELF_EXE`
246+
// environment variable to `processedExecutablePath`, otherwise
247+
// unset it if it is already set.
248+
char *envTermuxProcSelfExe = NULL;
249+
if (systemLinkerExec) {
250+
modifyEnv = true;
251+
logErrorVVerbose(LOG_TAG, "set_proc_self_exe_var_in_env: '%d'", true);
252+
253+
if (asprintf(&envTermuxProcSelfExe, "%s%s", ENV_PREFIX__TERMUX_EXEC__PROC_SELF_EXE, processedExecutablePath) == -1) {
254+
errno = ENOMEM;
255+
logStrerrorDebug(LOG_TAG, "asprintf failed for '%s%s'", ENV_PREFIX__TERMUX_EXEC__PROC_SELF_EXE, processedExecutablePath);
256+
return -1;
257+
}
258+
} else {
259+
const char *proc_self_exe_var[] = { ENV_PREFIX__TERMUX_EXEC__PROC_SELF_EXE };
260+
if (areVarsInEnv(envp, proc_self_exe_var, 1)) {
261+
logErrorVVerbose(LOG_TAG, "unset_proc_self_exe_var_from_env: '%d'", true);
262+
modifyEnv = true;
263+
}
264+
}
265+
234266
logErrorVVerbose(LOG_TAG, "modify_env: '%d'", modifyEnv);
235267

236268

@@ -249,20 +281,25 @@ int execveInterceptInternal(const char *origExecutablePath, char *const argv[],
249281

250282

251283

252-
const bool modifyArgs = interpreterSet;
284+
const bool modifyArgs = systemLinkerExec || interpreterSet;
253285
logErrorVVerbose(LOG_TAG, "modify_args: '%d'", modifyArgs);
254286

255287
const char **newArgv = NULL;
256288
if (modifyArgs) {
257289
if (modifyExecArgs(argv, &newArgv, origExecutablePath, executablePath,
258-
interpreterSet, &info) != 0 ||
290+
interpreterSet, systemLinkerExec, &info) != 0 ||
259291
newArgv == NULL) {
260292
logErrorDebug(LOG_TAG, "Failed to create modified exec args");
261293
free(envTermuxProcSelfExe);
262294
free(newEnvp);
263295
return -1;
264296
}
265297

298+
// Replace executable path if wrapping with linker.
299+
if (systemLinkerExec) {
300+
executablePath = SYSTEM_LINKER_PATH;
301+
}
302+
266303
argv = (char **) newArgv;
267304
}
268305

@@ -468,6 +505,97 @@ int inspectFileHeader(const char *termuxPrefixDir, char *header, size_t headerLe
468505

469506

470507

508+
int shouldSystemLinkerExec(const char *executablePath) {
509+
int systemLinkerExecConfig = getTermuxExecSystemLinkerExecConfig();
510+
logErrorVVerbose(LOG_TAG, "system_linker_exec_config: '%d'", systemLinkerExecConfig);
511+
512+
bool systemLinkerExec = false;
513+
if (systemLinkerExecConfig == 0) { // disable
514+
systemLinkerExec = false;
515+
516+
} else if (systemLinkerExecConfig == 2) { // force
517+
bool systemLinkerExecAvailable = false;
518+
systemLinkerExecAvailable = getAndroidBuildVersionSdk() >= 29;
519+
logErrorVVerbose(LOG_TAG, "system_linker_exec_available: '%d'", systemLinkerExecAvailable);
520+
521+
if (systemLinkerExecAvailable) {
522+
int isExecutableUnderTermuxAppDataDir = isPathUnderTermuxAppDataDir(LOG_TAG,
523+
executablePath, NULL, NULL);
524+
if (isExecutableUnderTermuxAppDataDir < 0) {
525+
return -1;
526+
}
527+
logErrorVVerbose(LOG_TAG, "isExecutableUnderTermuxAppDataDir: '%d'",
528+
isExecutableUnderTermuxAppDataDir == 0 ? true : false);
529+
530+
systemLinkerExec = isExecutableUnderTermuxAppDataDir == 0;
531+
}
532+
533+
} else { // enable
534+
if (systemLinkerExecConfig != 1) {
535+
logErrorDebug(LOG_TAG, "Warning: Ignoring invalid system_linker_exec_config value and using '1' instead");
536+
}
537+
538+
bool appDataFileExecExempted = false;
539+
(void)appDataFileExecExempted;
540+
541+
if (getAndroidBuildVersionSdk() >= 29) {
542+
// If running as root or shell user, then the process will
543+
// be assigned a different process context like
544+
// `PROCESS_CONTEXT__AOSP_SU`,
545+
// `PROCESS_CONTEXT__MAGISK_SU` or
546+
// `PROCESS_CONTEXT__SHELL`, which will not be the same
547+
// as the one that's exported in
548+
// `ENV__TERMUX__SE_PROCESS_CONTEXT`, so we need to check
549+
// effective uid equals `0` or `2000` instead. Moreover,
550+
// other su providers may have different contexts, so we
551+
// cannot just check AOSP or MAGISK contexts.
552+
// - https://man7.org/linux/man-pages/man2/getuid.2.html
553+
uid_t uid = geteuid();
554+
if (uid == 0 || uid == 2000) {
555+
logErrorVVerbose(LOG_TAG, "uid: '%d'", uid);
556+
appDataFileExecExempted = true;
557+
} else {
558+
char seProcessContext[80];
559+
bool getSeProcessContextSuccess = false;
560+
561+
if (getSeProcessContextFromEnv(LOG_TAG, ENV__TERMUX__SE_PROCESS_CONTEXT,
562+
seProcessContext, sizeof(seProcessContext))) {
563+
logErrorVVerbose(LOG_TAG, "se_process_context_from_env: '%s'", seProcessContext);
564+
getSeProcessContextSuccess = true;
565+
} else if (getSeProcessContextFromFile(LOG_TAG,
566+
seProcessContext, sizeof(seProcessContext))) {
567+
logErrorVVerbose(LOG_TAG, "se_process_context_from_file: '%s'", seProcessContext);
568+
getSeProcessContextSuccess = true;
569+
}
570+
571+
if (getSeProcessContextSuccess) {
572+
appDataFileExecExempted = stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_25) ||
573+
stringStartsWith(seProcessContext, PROCESS_CONTEXT_PREFIX__UNTRUSTED_APP_27);
574+
}
575+
}
576+
577+
logErrorVVerbose(LOG_TAG, "app_data_file_exec_exempted: '%d'", appDataFileExecExempted);
578+
579+
if (!appDataFileExecExempted) {
580+
int isExecutableUnderTermuxAppDataDir = isPathUnderTermuxAppDataDir(LOG_TAG,
581+
executablePath, NULL, NULL);
582+
if (isExecutableUnderTermuxAppDataDir < 0) {
583+
return -1;
584+
}
585+
586+
systemLinkerExec = isExecutableUnderTermuxAppDataDir == 0;
587+
logErrorVVerbose(LOG_TAG, "is_executable_under_termux_app_data_dir: '%d'", systemLinkerExec);
588+
}
589+
}
590+
}
591+
592+
logErrorVVerbose(LOG_TAG, "system_linker_exec: '%d'", systemLinkerExec);
593+
594+
return 1 ? systemLinkerExec : 0;
595+
}
596+
597+
598+
471599
bool shouldUnsetLDVarsFromEnv(bool isNonNativeElf, const char *executablePath) {
472600
return isNonNativeElf ||
473601
(stringStartsWith(executablePath, "/system/") &&
@@ -553,7 +681,7 @@ int modifyExecEnv(char *const *envp, char ***newEnvpPointer,
553681

554682
int modifyExecArgs(char *const *argv, const char ***newArgvPointer,
555683
const char *origExecutablePath, const char *executablePath,
556-
bool interpreterSet, struct FileHeaderInfo *info) {
684+
bool interpreterSet, bool systemLinkerExec, struct FileHeaderInfo *info) {
557685
int argsCount = 0;
558686
while (argv[argsCount] != NULL) {
559687
argsCount++;
@@ -579,6 +707,11 @@ int modifyExecArgs(char *const *argv, const char ***newArgvPointer,
579707
newArgv[index++] = argv[0];
580708
}
581709

710+
// Add executable path if wrapping with linker.
711+
if (systemLinkerExec) {
712+
newArgv[index++] = executablePath;
713+
}
714+
582715
// Add interpreter argument and script path if executing a script with shebang.
583716
if (interpreterSet) {
584717
if (info->interpreterArg != NULL) {

lib/termux-exec_c/src/termux/shell/command/environment/termux_exec/TermuxExecShellEnvironment.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,18 @@ int getTermuxExecLogLevel() {
2121
bool isTermuxExecExecveInterceptEnabled() {
2222
return getBoolEnvValue(ENV__TERMUX_EXEC__INTERCEPT_EXECVE, E_DEF_VAL__TERMUX_EXEC__INTERCEPT_EXECVE);
2323
}
24+
25+
int getTermuxExecSystemLinkerExecConfig() {
26+
int def = E_DEF_VAL__TERMUX_EXEC__SYSTEM_LINKER_EXEC;
27+
const char* value = getenv(ENV__TERMUX_EXEC__SYSTEM_LINKER_EXEC);
28+
if (value == NULL || strlen(value) < 1) {
29+
return def;
30+
} else if (strcmp(value, "disable") == 0) {
31+
return 0;
32+
} else if (strcmp(value, "enable") == 0) {
33+
return 1;
34+
} else if (strcmp(value, "force") == 0) {
35+
return 2;
36+
}
37+
return def;
38+
}

0 commit comments

Comments
 (0)