From cfd070f33cbacb654c7806fad7c85965d99cb7c7 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 29 Jul 2025 10:32:15 +0800 Subject: [PATCH] kernel: Add Hot Update Rescan Manager feature for dynamic signatures --- kernel/dynamic_sign.c | 49 ++++++++++++++++++++++++++++++++++++----- kernel/dynamic_sign.h | 4 ++++ kernel/throne_tracker.c | 20 +++++++++++++---- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/kernel/dynamic_sign.c b/kernel/dynamic_sign.c index 3ae06e66..bb46704a 100644 --- a/kernel/dynamic_sign.c +++ b/kernel/dynamic_sign.c @@ -19,6 +19,7 @@ #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" #include "manager.h" +#include "throne_tracker.h" #define MAX_MANAGERS 2 @@ -34,10 +35,11 @@ static struct manager_info active_managers[MAX_MANAGERS]; static DEFINE_SPINLOCK(managers_lock); static DEFINE_SPINLOCK(dynamic_sign_lock); -// Work queues for persistent storage +// Work queues for persistent storage and manager rescanning static struct work_struct ksu_save_dynamic_sign_work; static struct work_struct ksu_load_dynamic_sign_work; static struct work_struct ksu_clear_dynamic_sign_work; +static struct work_struct ksu_rescan_manager_work; bool ksu_is_dynamic_sign_enabled(void) { @@ -162,7 +164,7 @@ int ksu_get_manager_signature_index(uid_t uid) return signature_index; } -static void clear_all_managers(void) +static void clear_dynamic_managers_only(void) { unsigned long flags; int i; @@ -215,6 +217,29 @@ int ksu_get_active_managers(struct manager_list_info *info) return 0; } + +// Manager rescanning work handler +void ksu_rescan_manager_work_handler(struct work_struct *work) +{ + pr_info("Starting manager rescan for dynamic sign changes\n"); + + // Clear only dynamic managers, preserve default manager + clear_dynamic_managers_only(); + + // Note: We preserve the traditional manager (index 0) and only rescan for dynamic managers + pr_info("Preserved traditional manager, rescanning for dynamic managers\n"); + + // Trigger manager scanning + ksu_track_throne(); + + pr_info("Manager rescan completed\n"); +} + +bool ksu_trigger_manager_rescan(void) +{ + return ksu_queue_work(&ksu_rescan_manager_work); +} + static void do_save_dynamic_sign(struct work_struct *work) { u32 magic = DYNAMIC_SIGN_FILE_MAGIC; @@ -413,6 +438,10 @@ int ksu_handle_dynamic_sign(struct dynamic_sign_user_config *config) persistent_dynamic_sign(); pr_info("dynamic sign updated: size=0x%x, hash=%.16s... (multi-manager enabled)\n", config->size, config->hash); + + // Always trigger manager rescan when dynamic sign is set + pr_info("Dynamic sign set, triggering manager rescan\n"); + ksu_trigger_manager_rescan(); break; case DYNAMIC_SIGN_OP_GET: @@ -437,12 +466,18 @@ int ksu_handle_dynamic_sign(struct dynamic_sign_user_config *config) strcpy(dynamic_sign.hash, "0000000000000000000000000000000000000000000000000000000000000000"); dynamic_sign.is_set = 0; spin_unlock_irqrestore(&dynamic_sign_lock, flags); - clear_all_managers(); + + // Clear only dynamic managers, preserve default manager + clear_dynamic_managers_only(); // Clear file using the same method as save clear_dynamic_sign_file(); pr_info("Dynamic sign config cleared (multi-manager disabled)\n"); + + // Always trigger manager rescan when dynamic sign is cleared + pr_info("Dynamic sign cleared, triggering manager rescan\n"); + ksu_trigger_manager_rescan(); break; default: @@ -465,22 +500,24 @@ void ksu_dynamic_sign_init(void) INIT_WORK(&ksu_save_dynamic_sign_work, do_save_dynamic_sign); INIT_WORK(&ksu_load_dynamic_sign_work, do_load_dynamic_sign); INIT_WORK(&ksu_clear_dynamic_sign_work, do_clear_dynamic_sign_file); + INIT_WORK(&ksu_rescan_manager_work, ksu_rescan_manager_work_handler); // Initialize manager slots for (i = 0; i < MAX_MANAGERS; i++) { active_managers[i].is_active = false; } - pr_info("Dynamic sign initialized with conditional multi-manager support\n"); + pr_info("Dynamic sign initialized with conditional multi-manager support and rescan capability\n"); } void ksu_dynamic_sign_exit(void) { - clear_all_managers(); + // Clear only dynamic managers on exit, preserve default manager + clear_dynamic_managers_only(); // Save current config before exit do_save_dynamic_sign(NULL); - pr_info("Dynamic sign exited with persistent storage\n"); + pr_info("Dynamic sign exited, cleared dynamic managers, preserved default manager\n"); } // Get dynamic sign configuration for signature verification diff --git a/kernel/dynamic_sign.h b/kernel/dynamic_sign.h index 37b9d0e1..5d38a500 100644 --- a/kernel/dynamic_sign.h +++ b/kernel/dynamic_sign.h @@ -37,4 +37,8 @@ int ksu_get_active_managers(struct manager_list_info *info); // Multi-manager APK verification bool ksu_is_multi_manager_apk(char *path, int *signature_index); +// Manager rescanning functionality +bool ksu_trigger_manager_rescan(void); +void ksu_rescan_manager_work_handler(struct work_struct *work); + #endif \ No newline at end of file diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index a42d32c3..5a05d521 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -12,6 +12,7 @@ #include "manager.h" #include "throne_tracker.h" #include "kernel_compat.h" +#include "dynamic_sign.h" uid_t ksu_manager_uid = KSU_INVALID_UID; @@ -385,7 +386,7 @@ void track_throne() struct uid_data *np; struct uid_data *n; - // first, check if manager_uid exist! + // Check if any manager exists (traditional or dynamic) bool manager_exist = false; list_for_each_entry (np, &uid_list, list) { // if manager is installed in work profile, the uid in packages.list is still equals main profile @@ -395,9 +396,15 @@ void track_throne() manager_exist = true; break; } - - if (ksu_is_any_manager(np->uid)) { - manager_exist = true; + } + + // Check for dynamic managers + if (!manager_exist && ksu_is_dynamic_sign_enabled()) { + list_for_each_entry (np, &uid_list, list) { + if (ksu_is_any_manager(np->uid)) { + manager_exist = true; + break; + } } } @@ -410,6 +417,11 @@ void track_throne() pr_info("Searching manager...\n"); search_manager("/data/app", 2, &uid_list); pr_info("Search manager finished\n"); + } else { + // Always perform search when called from dynamic sign rescan + pr_info("Performing manager search (may be from dynamic sign rescan)\n"); + search_manager("/data/app", 2, &uid_list); + pr_info("Manager search completed\n"); } prune: