You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
fix: root related mounts leak in KernelSU in isolated services
This commit fixes the leak of mounts in KernelSU with global umount disabled in isolated services. This happens because KernelSU doesn't handle isolated services in kernel side, so we must find the main app UID and see if that UID is in denylist instead. With that, also improve APatch detection to take advantage of faster integer/UID comparison rather than always check process/string comparison, and only fallback to process name based if UID is not found. Co-Authored-By: nampud <nampud@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,9 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define IS_ISOLATED_SERVICE(uid) \
|
||||
((uid) >= 90000 && (uid) < 1000000)
|
||||
|
||||
/*
|
||||
* Bionic's atoi runs through strtol().
|
||||
* Use our own implementation for faster conversion.
|
||||
|
||||
@@ -722,7 +722,48 @@ void ZygiskContext::run_modules_post() {
|
||||
void ZygiskContext::app_specialize_pre() {
|
||||
flags[APP_SPECIALIZE] = true;
|
||||
|
||||
info_flags = rezygiskd_get_process_flags(g_ctx->args.app->uid, (const char *const)process);
|
||||
/* INFO: Isolated services have different UIDs than the main apps. Because
|
||||
numerous root implementations base themselves in the UID of the
|
||||
app, we need to ensure that the UID sent to ReZygiskd to search
|
||||
is the app's and not the isolated service, or else it will be
|
||||
able to bypass DenyList.
|
||||
|
||||
All apps, and isolated processes, of *third-party* applications will
|
||||
have their app_data_dir set. The system applications might not have
|
||||
one, however it is unlikely they will create an isolated process,
|
||||
and even if so, it should not impact in detections, performance or
|
||||
any area.
|
||||
*/
|
||||
uid_t uid = args.app->uid;
|
||||
if (IS_ISOLATED_SERVICE(uid) && args.app->app_data_dir) {
|
||||
/* INFO: If the app is an isolated service, we use the UID of the
|
||||
app's process data directory, which is the UID of the
|
||||
app itself, which root implementations actually use.
|
||||
*/
|
||||
const char *data_dir = env->GetStringUTFChars(args.app->app_data_dir, NULL);
|
||||
if (!data_dir) {
|
||||
LOGE("Failed to get app data directory");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (stat(data_dir, &st) == -1) {
|
||||
PLOGE("Failed to stat app data directory [%s]", data_dir);
|
||||
|
||||
env->ReleaseStringUTFChars(args.app->app_data_dir, data_dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uid = st.st_uid;
|
||||
|
||||
LOGD("Isolated service being related to UID %d, app data dir: %s", uid, data_dir);
|
||||
|
||||
env->ReleaseStringUTFChars(args.app->app_data_dir, data_dir);
|
||||
}
|
||||
|
||||
info_flags = rezygiskd_get_process_flags(uid, (const char *const)process);
|
||||
if (info_flags & PROCESS_IS_FIRST_STARTED) {
|
||||
/* INFO: To ensure we are really using a clean mount namespace, we use
|
||||
the first process it as reference for clean mount namespace,
|
||||
|
||||
@@ -168,22 +168,8 @@ bool apatch_uid_should_umount(uid_t uid, const char *const process) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* INFO: Some can take advantage of the UID being different in an app's
|
||||
isolated service, bypassing this check, so we must check against
|
||||
process name in case it is an isolated service. This can happen in
|
||||
all root implementations. */
|
||||
size_t targeted_process_length = 0;
|
||||
if (IS_ISOLATED_SERVICE(uid)) targeted_process_length = strlen(process);
|
||||
|
||||
for (size_t i = 0; i < config.size; i++) {
|
||||
if (IS_ISOLATED_SERVICE(uid)) {
|
||||
size_t config_process_length = strlen(config.configs[i].process);
|
||||
size_t smallest_process_length = targeted_process_length < config_process_length ? targeted_process_length : config_process_length;
|
||||
|
||||
if (strncmp(config.configs[i].process, process, smallest_process_length) != 0) continue;
|
||||
} else {
|
||||
if (config.configs[i].uid != uid) continue;
|
||||
}
|
||||
if (config.configs[i].uid != uid) continue;
|
||||
|
||||
/* INFO: This allow us to copy the information to avoid use-after-free */
|
||||
bool umount_needed = config.configs[i].umount_needed;
|
||||
@@ -193,6 +179,29 @@ bool apatch_uid_should_umount(uid_t uid, const char *const process) {
|
||||
return umount_needed;
|
||||
}
|
||||
|
||||
/* INFO: Isolated services have different UIDs than the main app, and
|
||||
while libzygisk.so has code to send the UID of the app related
|
||||
to the isolated service, we add this so that in case it fails,
|
||||
this should avoid it pass through as Mounted.
|
||||
*/
|
||||
if (IS_ISOLATED_SERVICE(uid)) {
|
||||
size_t targeted_process_length = strlen(process);
|
||||
|
||||
for (size_t i = 0; i < config.size; i++) {
|
||||
size_t config_process_length = strlen(config.configs[i].process);
|
||||
size_t smallest_process_length = targeted_process_length < config_process_length ? targeted_process_length : config_process_length;
|
||||
|
||||
if (strncmp(config.configs[i].process, process, smallest_process_length) != 0) continue;
|
||||
|
||||
/* INFO: This allow us to copy the information to avoid use-after-free */
|
||||
bool umount_needed = config.configs[i].umount_needed;
|
||||
|
||||
_apatch_free_package_config(&config);
|
||||
|
||||
return umount_needed;
|
||||
}
|
||||
}
|
||||
|
||||
_apatch_free_package_config(&config);
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user