kernel: Add Hot Update Rescan Manager feature for dynamic signatures

This commit is contained in:
ShirkNeko
2025-07-29 10:32:15 +08:00
parent 3ae1a3b10a
commit cfd070f33c
3 changed files with 63 additions and 10 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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: