You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
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>
223 lines
5.5 KiB
C
223 lines
5.5 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include "../constants.h"
|
|
#include "../utils.h"
|
|
#include "common.h"
|
|
|
|
#include "apatch.h"
|
|
|
|
void apatch_get_existence(struct root_impl_state *state) {
|
|
struct stat s;
|
|
if (stat("/data/adb/apd", &s) != 0) {
|
|
if (errno != ENOENT) {
|
|
LOGE("Failed to stat APatch apd binary: %s\n", strerror(errno));
|
|
}
|
|
errno = 0;
|
|
|
|
state->state = Inexistent;
|
|
|
|
return;
|
|
}
|
|
|
|
char *PATH = getenv("PATH");
|
|
if (PATH == NULL) {
|
|
LOGE("Failed to get PATH environment variable: %s\n", strerror(errno));
|
|
errno = 0;
|
|
|
|
state->state = Inexistent;
|
|
|
|
return;
|
|
}
|
|
|
|
if (strstr(PATH, "/data/adb/ap/bin") == NULL) {
|
|
LOGE("APatch's APD binary is not in PATH\n");
|
|
|
|
state->state = Inexistent;
|
|
|
|
return;
|
|
}
|
|
|
|
char apatch_version[32];
|
|
char *const argv[] = { "apd", "-V", NULL };
|
|
|
|
if (!exec_command(apatch_version, sizeof(apatch_version), "/data/adb/apd", argv)) {
|
|
LOGE("Failed to execute apd binary: %s\n", strerror(errno));
|
|
errno = 0;
|
|
|
|
state->state = Inexistent;
|
|
|
|
return;
|
|
}
|
|
|
|
int version = atoi(apatch_version + strlen("apd "));
|
|
|
|
if (version == 0) state->state = Abnormal;
|
|
else if (version >= MIN_APATCH_VERSION && version <= 999999) state->state = Supported;
|
|
else if (version >= 1 && version <= MIN_APATCH_VERSION - 1) state->state = TooOld;
|
|
else state->state = Abnormal;
|
|
}
|
|
|
|
struct package_config {
|
|
char *process;
|
|
uid_t uid;
|
|
bool root_granted;
|
|
bool umount_needed;
|
|
};
|
|
|
|
struct packages_config {
|
|
struct package_config *configs;
|
|
size_t size;
|
|
};
|
|
|
|
/* WARNING: Dynamic memory based */
|
|
bool _apatch_get_package_config(struct packages_config *restrict config) {
|
|
config->configs = NULL;
|
|
config->size = 0;
|
|
|
|
FILE *fp = fopen("/data/adb/ap/package_config", "r");
|
|
if (fp == NULL) {
|
|
LOGE("Failed to open APatch's package_config: %s\n", strerror(errno));
|
|
|
|
return false;
|
|
}
|
|
|
|
char line[1048];
|
|
/* INFO: Skip the CSV header */
|
|
if (fgets(line, sizeof(line), fp) == NULL) {
|
|
LOGE("Failed to read APatch's package_config header: %s\n", strerror(errno));
|
|
|
|
fclose(fp);
|
|
|
|
return false;
|
|
}
|
|
|
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
config->configs = realloc(config->configs, (config->size + 1) * sizeof(struct package_config));
|
|
if (config->configs == NULL) {
|
|
LOGE("Failed to realloc APatch config struct: %s\n", strerror(errno));
|
|
|
|
fclose(fp);
|
|
|
|
return false;
|
|
}
|
|
|
|
config->configs[config->size].process = strdup(strtok(line, ","));
|
|
|
|
char *exclude_str = strtok(NULL, ",");
|
|
if (exclude_str == NULL) continue;
|
|
|
|
char *allow_str = strtok(NULL, ",");
|
|
if (allow_str == NULL) continue;
|
|
|
|
char *uid_str = strtok(NULL, ",");
|
|
if (uid_str == NULL) continue;
|
|
|
|
config->configs[config->size].uid = (uid_t)atoi(uid_str);
|
|
config->configs[config->size].root_granted = strcmp(allow_str, "1") == 0;
|
|
config->configs[config->size].umount_needed = strcmp(exclude_str, "1") == 0;
|
|
|
|
config->size++;
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
void _apatch_free_package_config(struct packages_config *restrict config) {
|
|
for (size_t i = 0; i < config->size; i++) {
|
|
free(config->configs[i].process);
|
|
}
|
|
|
|
free(config->configs);
|
|
}
|
|
|
|
bool apatch_uid_granted_root(uid_t uid) {
|
|
struct packages_config config;
|
|
if (!_apatch_get_package_config(&config)) {
|
|
_apatch_free_package_config(&config);
|
|
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < config.size; i++) {
|
|
if (config.configs[i].uid != uid) continue;
|
|
|
|
/* INFO: This allow us to copy the information to avoid use-after-free */
|
|
bool root_granted = config.configs[i].root_granted;
|
|
|
|
_apatch_free_package_config(&config);
|
|
|
|
return root_granted;
|
|
}
|
|
|
|
_apatch_free_package_config(&config);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool apatch_uid_should_umount(uid_t uid, const char *const process) {
|
|
struct packages_config config;
|
|
if (!_apatch_get_package_config(&config)) {
|
|
_apatch_free_package_config(&config);
|
|
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < config.size; i++) {
|
|
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;
|
|
|
|
_apatch_free_package_config(&config);
|
|
|
|
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;
|
|
}
|
|
|
|
bool apatch_uid_is_manager(uid_t uid) {
|
|
struct stat s;
|
|
if (stat("/data/user_de/0/me.bmax.apatch", &s) == -1) {
|
|
if (errno != ENOENT) {
|
|
LOGE("Failed to stat APatch manager data directory: %s\n", strerror(errno));
|
|
}
|
|
errno = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
return s.st_uid == uid;
|
|
}
|