From f8abf097d7fdb325d51382f0976954d2b08d0ce8 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Sun, 14 Sep 2025 19:31:21 +0800 Subject: [PATCH] kernel: Improve dynamic manager functions and logging --- kernel/apk_sign.c | 23 ++-- kernel/dynamic_manager.c | 219 +++++++++++++++++++++------------------ kernel/dynamic_manager.h | 22 ++-- kernel/throne_tracker.c | 55 +++++++--- 4 files changed, 179 insertions(+), 140 deletions(-) diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c index c127a06a..3d3d0c5a 100644 --- a/kernel/apk_sign.c +++ b/kernel/apk_sign.c @@ -15,10 +15,10 @@ #endif #include "apk_sign.h" -#include "dynamic_manager.h" #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" #include "manager_sign.h" +#include "dynamic_manager.h" struct sdesc { struct shash_desc shash; @@ -88,19 +88,16 @@ static int ksu_sha256(const unsigned char *data, unsigned int datalen, return ret; } - -static struct dynamic_sign_key dynamic_sign = DYNAMIC_SIGN_DEFAULT_CONFIG; - static bool check_dynamic_sign(struct file *fp, u32 size4, loff_t *pos, int *matched_index) { - struct dynamic_sign_key current_dynamic_key = dynamic_sign; + unsigned int dynamic_size = 0; + const char *dynamic_hash = NULL; - if (ksu_get_dynamic_manager_config(¤t_dynamic_key.size, ¤t_dynamic_key.hash)) { - pr_debug("Using dynamic manager config: size=0x%x, hash=%.16s...\n", - current_dynamic_key.size, current_dynamic_key.hash); + if (!ksu_get_dynamic_manager_config(&dynamic_size, &dynamic_hash)) { + return false; } - if (size4 != current_dynamic_key.size) { + if (size4 != dynamic_size) { return false; } @@ -122,10 +119,10 @@ static bool check_dynamic_sign(struct file *fp, u32 size4, loff_t *pos, int *mat char hash_str[SHA256_DIGEST_SIZE * 2 + 1]; hash_str[SHA256_DIGEST_SIZE * 2] = '\0'; bin2hex(hash_str, digest, SHA256_DIGEST_SIZE); + + pr_info(DM_LOG_PREFIX "dynamic sign verified sha256: %s, expected: %s, (index: %d)\n", hash_str, dynamic_hash, DYNAMIC_SIGN_INDEX); - pr_info("sha256: %s, expected: %s, index: dynamic\n", hash_str, current_dynamic_key.hash); - - if (strcmp(current_dynamic_key.hash, hash_str) == 0) { + if (strcmp(dynamic_hash, hash_str) == 0) { if (matched_index) { *matched_index = DYNAMIC_SIGN_INDEX; } @@ -434,7 +431,7 @@ clean: if (check_multi_manager) { // 0: ShirkNeko/SukiSU, DYNAMIC_SIGN_INDEX : Dynamic Sign if (matched_index == 0 || matched_index == DYNAMIC_SIGN_INDEX) { - pr_info("Multi-manager APK detected (dynamic_manager enabled): signature_index=%d\n", matched_index); + pr_info("[ApkSign] multi-manager APK detected (signature_index=%d)\n", matched_index); return true; } return false; diff --git a/kernel/dynamic_manager.c b/kernel/dynamic_manager.c index 6f34d192..156e25b3 100644 --- a/kernel/dynamic_manager.c +++ b/kernel/dynamic_manager.c @@ -24,8 +24,8 @@ // Dynamic sign configuration static struct dynamic_manager_config dynamic_manager = { - .size = 0x300, - .hash = "0000000000000000000000000000000000000000000000000000000000000000", + .size = 0, + .hash = "", .is_set = 0 }; @@ -45,7 +45,7 @@ bool ksu_is_dynamic_manager_enabled(void) bool enabled; spin_lock_irqsave(&dynamic_manager_lock, flags); - enabled = dynamic_manager.is_set; + enabled = dynamic_manager.is_set && dynamic_manager.size > 0 && strlen(dynamic_manager.hash) == 64; spin_unlock_irqrestore(&dynamic_manager_lock, flags); return enabled; @@ -57,7 +57,6 @@ void ksu_add_manager(uid_t uid, int signature_index) int i; if (!ksu_is_dynamic_manager_enabled()) { - pr_info("Dynamic sign not enabled, skipping multi-manager add\n"); return; } @@ -68,7 +67,7 @@ void ksu_add_manager(uid_t uid, int signature_index) if (active_managers[i].is_active && active_managers[i].uid == uid) { active_managers[i].signature_index = signature_index; spin_unlock_irqrestore(&managers_lock, flags); - pr_info("Updated manager uid=%d, signature_index=%d\n", uid, signature_index); + pr_info(DM_LOG_PREFIX "updated manager uid=%d, signature_index=%d\n", uid, signature_index); return; } } @@ -80,13 +79,13 @@ void ksu_add_manager(uid_t uid, int signature_index) active_managers[i].signature_index = signature_index; active_managers[i].is_active = true; spin_unlock_irqrestore(&managers_lock, flags); - pr_info("Added manager uid=%d, signature_index=%d\n", uid, signature_index); + pr_info(DM_LOG_PREFIX "added manager uid=%d, signature_index=%d\n", uid, signature_index); return; } } spin_unlock_irqrestore(&managers_lock, flags); - pr_warn("Failed to add manager, no free slots\n"); + pr_warn(DM_LOG_PREFIX "failed to add manager, no free slots\n"); } void ksu_remove_manager(uid_t uid) @@ -103,7 +102,7 @@ void ksu_remove_manager(uid_t uid) for (i = 0; i < MAX_MANAGERS; i++) { if (active_managers[i].is_active && active_managers[i].uid == uid) { active_managers[i].is_active = false; - pr_info("Removed manager uid=%d\n", uid); + pr_info(DM_LOG_PREFIX "removed manager uid=%d\n", uid); break; } } @@ -142,7 +141,7 @@ int ksu_get_manager_signature_index(uid_t uid) // Check traditional manager first if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) { - return DYNAMIC_SIGN_INDEX; + return 0; } if (!ksu_is_dynamic_manager_enabled()) { @@ -162,57 +161,32 @@ int ksu_get_manager_signature_index(uid_t uid) return signature_index; } -static void clear_dynamic_manager(void) +static void ksu_invalidate_dynamic_managers(void) { unsigned long flags; int i; + bool had_active = false; spin_lock_irqsave(&managers_lock, flags); for (i = 0; i < MAX_MANAGERS; i++) { if (active_managers[i].is_active) { - pr_info("Clearing dynamic manager uid=%d (signature_index=%d) for rescan\n", - active_managers[i].uid, active_managers[i].signature_index); + pr_info(DM_LOG_PREFIX "invalidating dynamic manager uid=%d\n", active_managers[i].uid); active_managers[i].is_active = false; + had_active = true; } } spin_unlock_irqrestore(&managers_lock, flags); + + if (had_active) { + pr_info(DM_LOG_PREFIX "all dynamic managers invalidated\n"); + } } -int ksu_get_active_managers(struct manager_list_info *info) +static void clear_dynamic_manager(void) { - unsigned long flags; - int i, count = 0; - - if (!info) { - return -EINVAL; - } - - // Add traditional manager first - if (ksu_manager_uid != KSU_INVALID_UID && count < 2) { - info->managers[count].uid = ksu_manager_uid; - info->managers[count].signature_index = 0; - count++; - } - - // Add dynamic managers - if (ksu_is_dynamic_manager_enabled()) { - spin_lock_irqsave(&managers_lock, flags); - - for (i = 0; i < MAX_MANAGERS && count < 2; i++) { - if (active_managers[i].is_active) { - info->managers[count].uid = active_managers[i].uid; - info->managers[count].signature_index = active_managers[i].signature_index; - count++; - } - } - - spin_unlock_irqrestore(&managers_lock, flags); - } - - info->count = count; - return 0; + ksu_invalidate_dynamic_managers(); } static void do_save_dynamic_manager(struct work_struct *work) @@ -229,34 +203,23 @@ static void do_save_dynamic_manager(struct work_struct *work) spin_unlock_irqrestore(&dynamic_manager_lock, flags); if (!config_to_save.is_set) { - pr_info("Dynamic sign config not set, skipping save\n"); return; } fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (IS_ERR(fp)) { - pr_err("save_dynamic_manager create file failed: %ld\n", PTR_ERR(fp)); + pr_err(DM_LOG_PREFIX "save config failed: %ld\n", PTR_ERR(fp)); return; } - if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) { - pr_err("save_dynamic_manager write magic failed.\n"); - goto exit; + if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) || + ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != sizeof(version) || + ksu_kernel_write_compat(fp, &config_to_save, sizeof(config_to_save), &off) != sizeof(config_to_save)) { + pr_err(DM_LOG_PREFIX "save config write failed\n"); + } else { + pr_info(DM_LOG_PREFIX "config saved successfully\n"); } - if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != sizeof(version)) { - pr_err("save_dynamic_manager write version failed.\n"); - goto exit; - } - - if (ksu_kernel_write_compat(fp, &config_to_save, sizeof(config_to_save), &off) != sizeof(config_to_save)) { - pr_err("save_dynamic_manager write config failed.\n"); - goto exit; - } - - pr_info("Dynamic sign config saved successfully\n"); - -exit: filp_close(fp, 0); } @@ -273,45 +236,36 @@ static void do_load_dynamic_manager(struct work_struct *work) fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_MANAGER, O_RDONLY, 0); if (IS_ERR(fp)) { - if (PTR_ERR(fp) == -ENOENT) { - pr_info("No saved dynamic manager config found\n"); - } else { - pr_err("load_dynamic_manager open file failed: %ld\n", PTR_ERR(fp)); + if (PTR_ERR(fp) != -ENOENT) { + pr_err(DM_LOG_PREFIX "load config failed: %ld\n", PTR_ERR(fp)); } return; } if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) || magic != DYNAMIC_MANAGER_FILE_MAGIC) { - pr_err("dynamic manager file invalid magic: %x!\n", magic); + pr_err(DM_LOG_PREFIX "invalid magic: %x\n", magic); goto exit; } if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != sizeof(version)) { - pr_err("dynamic manager read version failed\n"); + pr_err(DM_LOG_PREFIX "read version failed\n"); goto exit; } - pr_info("dynamic manager file version: %d\n", version); - ret = ksu_kernel_read_compat(fp, &loaded_config, sizeof(loaded_config), &off); - if (ret <= 0) { - pr_info("load_dynamic_manager read err: %zd\n", ret); - goto exit; - } - if (ret != sizeof(loaded_config)) { - pr_err("load_dynamic_manager read incomplete config: %zd/%zu\n", ret, sizeof(loaded_config)); + pr_err(DM_LOG_PREFIX "read config failed: %zd\n", ret); goto exit; } if (loaded_config.size < 0x100 || loaded_config.size > 0x1000) { - pr_err("Invalid saved config size: 0x%x\n", loaded_config.size); + pr_err(DM_LOG_PREFIX "invalid size: 0x%x\n", loaded_config.size); goto exit; } if (strlen(loaded_config.hash) != 64) { - pr_err("Invalid saved config hash length: %zu\n", strlen(loaded_config.hash)); + pr_err(DM_LOG_PREFIX "invalid hash length: %zu\n", strlen(loaded_config.hash)); goto exit; } @@ -319,7 +273,7 @@ static void do_load_dynamic_manager(struct work_struct *work) for (i = 0; i < 64; i++) { char c = loaded_config.hash[i]; if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) { - pr_err("Invalid saved config hash character at position %d: %c\n", i, c); + pr_err(DM_LOG_PREFIX "invalid hash character at position %d: %c\n", i, c); goto exit; } } @@ -328,7 +282,7 @@ static void do_load_dynamic_manager(struct work_struct *work) dynamic_manager = loaded_config; spin_unlock_irqrestore(&dynamic_manager_lock, flags); - pr_info("Dynamic sign config loaded: size=0x%x, hash=%.16s...\n", + pr_info(DM_LOG_PREFIX "config loaded: size=0x%x, hash=%.16s...\n", loaded_config.size, loaded_config.hash); exit: @@ -350,15 +304,13 @@ static void do_clear_dynamic_manager(struct work_struct *work) fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (IS_ERR(fp)) { - pr_err("clear_dynamic_manager create file failed: %ld\n", PTR_ERR(fp)); + pr_err(DM_LOG_PREFIX "clear config file failed: %ld\n", PTR_ERR(fp)); return; } // Write null bytes to overwrite the file content if (ksu_kernel_write_compat(fp, zero_buffer, sizeof(zero_buffer), &off) != sizeof(zero_buffer)) { - pr_err("clear_dynamic_manager write null bytes failed.\n"); - } else { - pr_info("Dynamic sign config file cleared successfully\n"); + pr_err(DM_LOG_PREFIX "clear config write failed\n"); } filp_close(fp, 0); @@ -382,12 +334,12 @@ int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config) switch (config->operation) { case DYNAMIC_MANAGER_OP_SET: if (config->size < 0x100 || config->size > 0x1000) { - pr_err("invalid size: 0x%x\n", config->size); + pr_err(DM_LOG_PREFIX "invalid size: 0x%x\n", config->size); return -EINVAL; } if (strlen(config->hash) != 64) { - pr_err("invalid hash length: %zu\n", strlen(config->hash)); + pr_err(DM_LOG_PREFIX "invalid hash length: %zu\n", strlen(config->hash)); return -EINVAL; } @@ -395,11 +347,13 @@ int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config) for (i = 0; i < 64; i++) { char c = config->hash[i]; if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) { - pr_err("invalid hash character at position %d: %c\n", i, c); + pr_err(DM_LOG_PREFIX "invalid hash character at position %d: %c\n", i, c); return -EINVAL; } } + clear_dynamic_manager(); + spin_lock_irqsave(&dynamic_manager_lock, flags); dynamic_manager.size = config->size; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) @@ -411,13 +365,13 @@ int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config) spin_unlock_irqrestore(&dynamic_manager_lock, flags); persistent_dynamic_manager(); - pr_info("dynamic manager updated: size=0x%x, hash=%.16s... (multi-manager enabled)\n", + pr_info(DM_LOG_PREFIX "config updated and activated: size=0x%x, hash=%.16s...\n", config->size, config->hash); break; case DYNAMIC_MANAGER_OP_GET: spin_lock_irqsave(&dynamic_manager_lock, flags); - if (dynamic_manager.is_set) { + if (dynamic_manager.is_set && dynamic_manager.size > 0 && strlen(dynamic_manager.hash) == 64) { config->size = dynamic_manager.size; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) strscpy(config->hash, dynamic_manager.hash, sizeof(config->hash)); @@ -432,23 +386,24 @@ int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config) break; case DYNAMIC_MANAGER_OP_CLEAR: + // 改进:先无效化所有动态管理器 + pr_info(DM_LOG_PREFIX "clearing dynamic manager config\n"); + clear_dynamic_manager(); + spin_lock_irqsave(&dynamic_manager_lock, flags); - dynamic_manager.size = 0x300; - strcpy(dynamic_manager.hash, "0000000000000000000000000000000000000000000000000000000000000000"); + dynamic_manager.size = 0; + memset(dynamic_manager.hash, 0, sizeof(dynamic_manager.hash)); dynamic_manager.is_set = 0; spin_unlock_irqrestore(&dynamic_manager_lock, flags); - // Clear only dynamic managers, preserve default manager - clear_dynamic_manager(); - - // Clear file using the same method as save + // Clear file clear_dynamic_manager_file(); - pr_info("Dynamic sign config cleared (multi-manager disabled)\n"); + pr_info(DM_LOG_PREFIX "config cleared\n"); break; default: - pr_err("Invalid dynamic manager operation: %d\n", config->operation); + pr_err(DM_LOG_PREFIX "invalid operation: %d\n", config->operation); return -EINVAL; } @@ -475,7 +430,7 @@ void ksu_dynamic_manager_init(void) ksu_load_dynamic_manager(); - pr_info("Dynamic sign initialized with conditional multi-manager support\n"); + pr_info(DM_LOG_PREFIX "init\n"); } void ksu_dynamic_manager_exit(void) @@ -484,7 +439,7 @@ void ksu_dynamic_manager_exit(void) // Save current config before exit do_save_dynamic_manager(NULL); - pr_info("Dynamic sign exited with persistent storage\n"); + pr_info(DM_LOG_PREFIX "exited\n"); } // Get dynamic manager configuration for signature verification @@ -494,7 +449,7 @@ bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash) bool valid = false; spin_lock_irqsave(&dynamic_manager_lock, flags); - if (dynamic_manager.is_set) { + if (dynamic_manager.is_set && dynamic_manager.size > 0 && strlen(dynamic_manager.hash) == 64) { if (size) *size = dynamic_manager.size; if (hash) *hash = dynamic_manager.hash; valid = true; @@ -502,4 +457,68 @@ bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash) spin_unlock_irqrestore(&dynamic_manager_lock, flags); return valid; +} + + +int ksu_get_active_managers(struct manager_list_info *info) +{ + unsigned long flags; + int i, count = 0; + + if (!info) { + return -EINVAL; + } + + memset(info, 0, sizeof(*info)); + + if (ksu_manager_uid != KSU_INVALID_UID && count < ARRAY_SIZE(info->managers)) { + info->managers[count].uid = ksu_manager_uid; + info->managers[count].signature_index = 0; + count++; + pr_info(DM_LOG_PREFIX "added traditional manager: uid=%d\n", ksu_manager_uid); + } + + if (ksu_is_dynamic_manager_enabled() && count < ARRAY_SIZE(info->managers)) { + spin_lock_irqsave(&managers_lock, flags); + + for (i = 0; i < MAX_MANAGERS && count < ARRAY_SIZE(info->managers); i++) { + if (active_managers[i].is_active) { + info->managers[count].uid = active_managers[i].uid; + info->managers[count].signature_index = active_managers[i].signature_index; + count++; + pr_info(DM_LOG_PREFIX "added dynamic manager: uid=%d, signature_index=%d\n", + active_managers[i].uid, active_managers[i].signature_index); + } + } + + spin_unlock_irqrestore(&managers_lock, flags); + } + + info->count = count; + pr_info(DM_LOG_PREFIX "total active managers: %d\n", count); + return 0; +} + +bool ksu_has_dynamic_managers(void) +{ + unsigned long flags; + bool has_managers = false; + int i; + + if (!ksu_is_dynamic_manager_enabled()) { + return false; + } + + spin_lock_irqsave(&managers_lock, flags); + + for (i = 0; i < MAX_MANAGERS; i++) { + if (active_managers[i].is_active) { + has_managers = true; + break; + } + } + + spin_unlock_irqrestore(&managers_lock, flags); + + return has_managers; } \ No newline at end of file diff --git a/kernel/dynamic_manager.h b/kernel/dynamic_manager.h index 1b5a5cbd..048331ba 100644 --- a/kernel/dynamic_manager.h +++ b/kernel/dynamic_manager.h @@ -9,14 +9,16 @@ #define KERNEL_SU_DYNAMIC_MANAGER "/data/adb/ksu/.dynamic_manager" #define DYNAMIC_SIGN_INDEX 100 +#define DM_LOG_PREFIX "[Dynamic Manager] " + struct dynamic_sign_key { unsigned int size; const char *hash; }; #define DYNAMIC_SIGN_DEFAULT_CONFIG { \ - .size = 0x300, \ - .hash = "0000000000000000000000000000000000000000000000000000000000000000" \ + .size = 0, \ + .hash = "" \ } struct dynamic_manager_config { @@ -31,21 +33,17 @@ struct manager_info { bool is_active; }; -// Dynamic sign operations -void ksu_dynamic_manager_init(void); -void ksu_dynamic_manager_exit(void); -int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config); -bool ksu_load_dynamic_manager(void); bool ksu_is_dynamic_manager_enabled(void); - -// Multi-manager operations void ksu_add_manager(uid_t uid, int signature_index); void ksu_remove_manager(uid_t uid); bool ksu_is_any_manager(uid_t uid); int ksu_get_manager_signature_index(uid_t uid); -int ksu_get_active_managers(struct manager_list_info *info); - -// Configuration access for signature verification +int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config); +bool ksu_load_dynamic_manager(void); +void ksu_dynamic_manager_init(void); +void ksu_dynamic_manager_exit(void); bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash); +int ksu_get_active_managers(struct manager_list_info *info); +bool ksu_has_dynamic_managers(void); #endif \ No newline at end of file diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index 9b169d20..011eea8b 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -74,6 +74,7 @@ struct my_dir_context { void *private_data; int depth; int *stop; + bool found_dynamic_manager; }; // https://docs.kernel.org/filesystems/porting.html // filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: callers never looked at specific -E... values anyway. -> iterate_shared() instances require no changes at all, all filldir_t ones in the tree converted. @@ -153,7 +154,7 @@ static void crown_manager(const char *apk, struct list_head *uid_data, pr_info("Crowning manager: %s(uid=%d, signature_index=%d)\n", pkg, np->uid, signature_index); - // Dynamic Sign index (1) or multi-manager signatures (2+) + // Dynamic Sign index (100) or multi-manager signatures (>= 2) if (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2) { ksu_add_manager(np->uid, signature_index); @@ -468,6 +469,7 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, // Check for dynamic sign or multi-manager signatures if (is_multi_manager && (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2)) { + my_ctx->found_dynamic_manager = true; crown_manager(dirpath, my_ctx->private_data, signature_index); struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC); @@ -478,12 +480,17 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, } } else if (is_manager_apk(dirpath)) { crown_manager(dirpath, my_ctx->private_data, 0); - *my_ctx->stop = 1; + + if (!my_ctx->found_dynamic_manager && !ksu_is_dynamic_manager_enabled()) { + *my_ctx->stop = 1; + } // Manager found, clear APK cache list - list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { - list_del(&pos->list); - kfree(pos); + if (!ksu_is_dynamic_manager_enabled()) { + list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { + list_del(&pos->list); + kfree(pos); + } } } else { struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC); @@ -506,6 +513,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) INIT_LIST_HEAD(&data_path_list); INIT_LIST_HEAD(&apk_path_hash_list); unsigned long data_app_magic = 0; + bool found_dynamic_manager = false; // Initialize APK cache list struct apk_path_hash *pos, *n; @@ -528,7 +536,8 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) .parent_dir = pos->dirpath, .private_data = uid_data, .depth = pos->depth, - .stop = &stop }; + .stop = &stop, + .found_dynamic_manager = false }; struct file *file; if (!stop) { @@ -558,13 +567,17 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) iterate_dir(file, &ctx.ctx); filp_close(file, NULL); + + if (ctx.found_dynamic_manager) { + found_dynamic_manager = true; + } } skip_iterate: list_del(&pos->list); if (pos != &data) kfree(pos); - } } + } // clear apk_path_hash_list unconditionally pr_info("search manager: cleanup!\n"); @@ -621,12 +634,16 @@ static void track_throne_function(void) } // Check for dynamic managers - if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { - list_for_each_entry (np, &uid_list, list) { + if (ksu_is_dynamic_manager_enabled()) { + dynamic_manager_exist = ksu_has_dynamic_managers(); + + if (!dynamic_manager_exist) { + list_for_each_entry (np, &uid_list, list) { // Check if this uid is a dynamic manager (not the traditional manager) - if (ksu_is_any_manager(np->uid) && np->uid != ksu_get_manager_uid()) { - dynamic_manager_exist = true; - break; + if (ksu_is_any_manager(np->uid) && np->uid != ksu_get_manager_uid()) { + dynamic_manager_exist = true; + break; + } } } } @@ -635,17 +652,25 @@ static void track_throne_function(void) if (ksu_is_manager_uid_valid()) { pr_info("manager is uninstalled, invalidate it!\n"); ksu_invalidate_manager_uid(); - goto prune; } pr_info("Searching manager...\n"); search_manager("/data/app", 2, &uid_list); pr_info("Search manager finished\n"); - } else if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { - // Always perform search when called from dynamic manager rescan + goto prune; + } + + // Always perform search when called from dynamic manager rescan + if (ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist) { pr_info("Dynamic sign enabled, Searching manager...\n"); search_manager("/data/app", 2, &uid_list); pr_info("Search Dynamic sign manager finished\n"); } + // If traditional manager exists but no dynamic manager instances found, do a full search + if (manager_exist && ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist) { + pr_info("Searching manager...\n"); + search_manager("/data/app", 2, &uid_list); + pr_info("Search manager finished\n"); + } prune: // then prune the allowlist