diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 9387e994..ceafa407 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -45,11 +45,14 @@ #include "throne_tracker.h" #include "throne_comm.h" #include "kernel_compat.h" - -#include "kpm/kpm.h" #include "dynamic_manager.h" +#ifdef CONFIG_KPM +#include "kpm/kpm.h" +#endif + static bool ksu_module_mounted = false; +bool ksu_uid_scanner_enabled = false; extern int handle_sepolicy(unsigned long arg3, void __user *arg4); @@ -224,10 +227,11 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname, new_dentry->d_iname, buf); + if (ksu_uid_scanner_enabled) { + ksu_request_userspace_scan(); + } + track_throne(); - - // Also request userspace scan for next time - ksu_request_userspace_scan(); return 0; } @@ -265,6 +269,20 @@ static bool is_system_bin_su() return (current->mm->exe_file && !strcmp(current->mm->exe_file->f_path.dentry->d_name.name, "su")); } +static void init_uid_scanner(void) +{ + ksu_uid_init(); + do_load_throne_state(NULL); + + if (ksu_uid_scanner_enabled) { + int ret = ksu_throne_comm_init(); + if (ret != 0) { + pr_err("Failed to initialize throne communication: %d\n", ret); + } + } +} + + int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { @@ -412,8 +430,8 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, post_fs_data_lock = true; pr_info("post-fs-data triggered\n"); on_post_fs_data(); - // Initialize throne communication - ksu_throne_comm_init(); + // Initialize UID scanner if enabled + init_uid_scanner(); // Initializing Dynamic Signatures ksu_dynamic_manager_init(); pr_info("Dynamic sign config loaded during post-fs-data\n"); @@ -625,6 +643,58 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } + // UID Scanner control command + if (arg2 == CMD_ENABLE_UID_SCANNER) { + if (arg3 == 0) { + // Get current status + bool status = ksu_uid_scanner_enabled; + if (copy_to_user((void __user *)arg4, &status, sizeof(status))) { + pr_err("uid_scanner: copy status failed\n"); + return 0; + } + } else if (arg3 == 1) { + // Enable/Disable toggle + bool enabled = (arg4 != 0); + + if (enabled == ksu_uid_scanner_enabled) { + pr_info("uid_scanner: no need to change, already %s\n", + enabled ? "enabled" : "disabled"); + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("uid_scanner: prctl reply error\n"); + } + return 0; + } + + if (enabled) { + // Enable UID scanner + int ret = ksu_throne_comm_init(); + if (ret != 0) { + pr_err("uid_scanner: failed to initialize: %d\n", ret); + return 0; + } + pr_info("uid_scanner: enabled\n"); + } else { + // Disable UID scanner + ksu_throne_comm_exit(); + pr_info("uid_scanner: disabled\n"); + } + + ksu_uid_scanner_enabled = enabled; + ksu_throne_comm_save_state(); + } else if (arg3 == 2) { + // Clear environment (force exit) + ksu_throne_comm_exit(); + ksu_uid_scanner_enabled = false; + ksu_throne_comm_save_state(); + pr_info("uid_scanner: environment cleared\n"); + } + + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("uid_scanner: prctl reply error\n"); + } + return 0; + } + return 0; } @@ -1072,6 +1142,7 @@ void __init ksu_core_init(void) void ksu_core_exit(void) { + ksu_uid_exit(); ksu_throne_comm_exit(); #ifdef CONFIG_KPROBE pr_info("ksu_core_kprobe_exit\n"); diff --git a/kernel/ksu.h b/kernel/ksu.h index 53201802..ba2010a3 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -30,6 +30,7 @@ #define CMD_HOOK_TYPE 101 #define CMD_DYNAMIC_MANAGER 103 #define CMD_GET_MANAGERS 104 +#define CMD_ENABLE_UID_SCANNER 105 #define EVENT_POST_FS_DATA 1 #define EVENT_BOOT_COMPLETED 2 diff --git a/kernel/throne_comm.c b/kernel/throne_comm.c index 97d8b18c..79acb6bd 100644 --- a/kernel/throne_comm.c +++ b/kernel/throne_comm.c @@ -7,12 +7,18 @@ #include "klog.h" #include "throne_comm.h" +#include "kernel_compat.h" #define PROC_UID_SCANNER "ksu_uid_scanner" +#define UID_SCANNER_STATE_FILE "/data/adb/ksu/.uid_scanner" static struct proc_dir_entry *proc_entry = NULL; static struct workqueue_struct *scanner_wq = NULL; static struct work_struct scan_work; +static struct work_struct ksu_state_save_work; +static struct work_struct ksu_state_load_work; + +extern bool ksu_uid_scanner_enabled; // Signal userspace to rescan static bool need_rescan = false; @@ -38,6 +44,67 @@ void ksu_handle_userspace_update(void) pr_info("userspace uid list updated\n"); } +static void do_save_throne_state(struct work_struct *work) +{ + struct file *fp; + char state_char = ksu_uid_scanner_enabled ? '1' : '0'; + loff_t off = 0; + + fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (IS_ERR(fp)) { + pr_err("save_throne_state create file failed: %ld\n", PTR_ERR(fp)); + return; + } + + if (ksu_kernel_write_compat(fp, &state_char, sizeof(state_char), &off) != sizeof(state_char)) { + pr_err("save_throne_state write failed\n"); + goto exit; + } + + pr_info("throne state saved: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled"); + +exit: + filp_close(fp, 0); +} + +void do_load_throne_state(struct work_struct *work) +{ + struct file *fp; + char state_char; + loff_t off = 0; + ssize_t ret; + + fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_info("throne state file not found, using default: disabled\n"); + ksu_uid_scanner_enabled = false; + return; + } + + ret = ksu_kernel_read_compat(fp, &state_char, sizeof(state_char), &off); + if (ret != sizeof(state_char)) { + pr_err("load_throne_state read err: %zd\n", ret); + ksu_uid_scanner_enabled = false; + goto exit; + } + + ksu_uid_scanner_enabled = (state_char == '1'); + pr_info("throne state loaded: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled"); + +exit: + filp_close(fp, 0); +} + +bool ksu_throne_comm_load_state(void) +{ + return ksu_queue_work(&ksu_state_load_work); +} + +void ksu_throne_comm_save_state(void) +{ + ksu_queue_work(&ksu_state_save_work); +} + static int uid_scanner_show(struct seq_file *m, void *v) { if (need_rescan) { @@ -122,4 +189,16 @@ void ksu_throne_comm_exit(void) } pr_info("throne communication cleaned up\n"); +} + +int ksu_uid_init(void) +{ + INIT_WORK(&ksu_state_save_work, do_save_throne_state); + INIT_WORK(&ksu_state_load_work, do_load_throne_state); + return 0; +} + +void ksu_uid_exit(void) +{ + do_save_throne_state(NULL); } \ No newline at end of file diff --git a/kernel/throne_comm.h b/kernel/throne_comm.h index eedf8c15..4deba2ab 100644 --- a/kernel/throne_comm.h +++ b/kernel/throne_comm.h @@ -9,4 +9,14 @@ int ksu_throne_comm_init(void); void ksu_throne_comm_exit(void); +int ksu_uid_init(void); + +void ksu_uid_exit(void); + +bool ksu_throne_comm_load_state(void); + +void ksu_throne_comm_save_state(void); + +void do_load_throne_state(struct work_struct *work); + #endif \ No newline at end of file diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index 45e07ad5..fcc881b2 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -569,15 +569,21 @@ static bool is_uid_exist(uid_t uid, char *package, void *data) return exist; } +extern bool ksu_uid_scanner_enabled; + void track_throne() { struct list_head uid_list; INIT_LIST_HEAD(&uid_list); - pr_info("track_throne triggered, attempting whitelist read\n"); - - // Try read whitelist first - int ret = read_uid_whitelist(&uid_list); + int ret; + + if (ksu_uid_scanner_enabled) { + // Try read whitelist first + ret = read_uid_whitelist(&uid_list); + } else { + ret = -1; + } if (ret < 0) { pr_info("whitelist read failed (%d), request userspace scan, falling back to user_de \n", ret); diff --git a/manager/app/src/main/cpp/jni.c b/manager/app/src/main/cpp/jni.c index 28627634..05c028c1 100644 --- a/manager/app/src/main/cpp/jni.c +++ b/manager/app/src/main/cpp/jni.c @@ -431,4 +431,16 @@ NativeBridge(verifyModuleSignature, jboolean, jstring modulePath) { LogDebug("verifyModuleSignature: not supported on non-ARM architecture"); return false; #endif +} + +NativeBridgeNP(isUidScannerEnabled, jboolean) { + return is_uid_scanner_enabled(); +} + +NativeBridge(setUidScannerEnabled, jboolean, jboolean enabled) { + return set_uid_scanner_enabled(enabled); +} + +NativeBridgeNP(clearUidScannerEnvironment, jboolean) { + return clear_uid_scanner_environment(); } \ No newline at end of file diff --git a/manager/app/src/main/cpp/ksu.c b/manager/app/src/main/cpp/ksu.c index 7c5a0479..1094a4b1 100644 --- a/manager/app/src/main/cpp/ksu.c +++ b/manager/app/src/main/cpp/ksu.c @@ -48,6 +48,7 @@ extern const char* zako_file_verrcidx2str(uint8_t index); #define CMD_GET_SUSFS_FEATURE_STATUS 102 #define CMD_DYNAMIC_MANAGER 103 #define CMD_GET_MANAGERS 104 +#define CMD_ENABLE_UID_SCANNER 105 #define DYNAMIC_MANAGER_OP_SET 0 #define DYNAMIC_MANAGER_OP_GET 1 @@ -249,4 +250,18 @@ bool verify_module_signature(const char* input) { LogDebug("verify_module_signature: not supported on non-ARM architecture, path=%s", input ? input : "null"); return false; #endif +} + +bool is_uid_scanner_enabled() { + bool status = false; + ksuctl(CMD_ENABLE_UID_SCANNER, (void*)0, &status); + return status; +} + +bool set_uid_scanner_enabled(bool enabled) { + return ksuctl(CMD_ENABLE_UID_SCANNER, (void*)1, (void*)enabled); +} + +bool clear_uid_scanner_environment() { + return ksuctl(CMD_ENABLE_UID_SCANNER, (void*)2, NULL); } \ No newline at end of file diff --git a/manager/app/src/main/cpp/ksu.h b/manager/app/src/main/cpp/ksu.h index 8df709dc..57c93833 100644 --- a/manager/app/src/main/cpp/ksu.h +++ b/manager/app/src/main/cpp/ksu.h @@ -137,4 +137,10 @@ bool get_managers_list(struct manager_list_info* info); bool verify_module_signature(const char* input); +bool is_uid_scanner_enabled(); + +bool set_uid_scanner_enabled(bool enabled); + +bool clear_uid_scanner_environment(); + #endif //KERNELSU_KSU_H \ No newline at end of file diff --git a/manager/app/src/main/java/com/sukisu/ultra/Natives.kt b/manager/app/src/main/java/com/sukisu/ultra/Natives.kt index 222df276..15721904 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/Natives.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/Natives.kt @@ -138,6 +138,26 @@ object Natives { // 模块签名验证 external fun verifyModuleSignature(modulePath: String): Boolean + /** + * Check if UID scanner is currently enabled + * @return true if UID scanner is enabled, false otherwise + */ + external fun isUidScannerEnabled(): Boolean + + /** + * Enable or disable UID scanner + * @param enabled true to enable, false to disable + * @return true if operation was successful, false otherwise + */ + external fun setUidScannerEnabled(enabled: Boolean): Boolean + + /** + * Clear UID scanner environment (force exit) + * This will forcefully stop all UID scanner operations and clear the environment + * @return true if operation was successful, false otherwise + */ + external fun clearUidScannerEnvironment(): Boolean + private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$" private const val NOBODY_UID = 9999 diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt index 1b3c7a06..2581a1c8 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt @@ -46,11 +46,7 @@ import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha import com.sukisu.ultra.ui.theme.getCardColors import com.sukisu.ultra.ui.theme.getCardElevation -import com.sukisu.ultra.ui.util.LocalSnackbarHost -import com.sukisu.ultra.ui.util.getBugreportFile -import com.sukisu.ultra.ui.util.getRootShell -import com.sukisu.ultra.ui.util.setUidAutoScan -import com.sukisu.ultra.ui.util.setUidMultiUserScan +import com.sukisu.ultra.ui.util.* import com.topjohnwu.superuser.ShellUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -181,6 +177,7 @@ fun SettingScreen(navigator: DestinationsNavigator) { forceSignatureVerification = enabled } ) + // UID 扫描开关 if (Natives.version >= Natives.MINIMAL_SUPPORTED_UID_SCANNER) { var uidAutoScanEnabled by rememberSaveable { mutableStateOf(prefs.getBoolean("uid_auto_scan", false)) @@ -189,6 +186,17 @@ fun SettingScreen(navigator: DestinationsNavigator) { var uidMultiUserScanEnabled by rememberSaveable { mutableStateOf(prefs.getBoolean("uid_multi_user_scan", false)) } + + LaunchedEffect(Unit) { + uidAutoScanEnabled = Natives.isUidScannerEnabled() + uidMultiUserScanEnabled = getUidMultiUserScan() + + prefs.edit { + putBoolean("uid_auto_scan", uidAutoScanEnabled) + putBoolean("uid_multi_user_scan", uidMultiUserScanEnabled) + } + } + // 用户态扫描应用列表开关 SwitchItem( icon = Icons.Filled.Scanner, @@ -281,6 +289,8 @@ fun SettingScreen(navigator: DestinationsNavigator) { uidMultiUserScanEnabled = false prefs.edit { putBoolean("uid_multi_user_scan", false) } + Natives.setUidScannerEnabled(false) + snackBarHost.showSnackbar(context.getString(R.string.clean_runtime_environment_success)) } else { snackBarHost.showSnackbar(context.getString(R.string.clean_runtime_environment_failed)) @@ -470,6 +480,7 @@ fun cleanRuntimeEnvironment(): Boolean { ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/uid_scanner") ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/ksu/bin/user_uid") ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/service.d/uid_scanner.sh") + Natives.clearUidScannerEnvironment() true } catch (_: Exception) { false diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt index 85d4f4d7..119e4f49 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt @@ -609,7 +609,10 @@ fun setUidAutoScan(enabled: Boolean): Boolean { val enableValue = if (enabled) 1 else 0 val cmd = "$targetPath --auto-scan $enableValue && $targetPath reload" val result = ShellUtils.fastCmdResult(shell, cmd) - return result + + val throneResult = Natives.setUidScannerEnabled(enabled) + + return result && throneResult } fun setUidMultiUserScan(enabled: Boolean): Boolean { @@ -623,3 +626,16 @@ fun setUidMultiUserScan(enabled: Boolean): Boolean { val result = ShellUtils.fastCmdResult(shell, cmd) return result } + +fun getUidMultiUserScan(): Boolean { + val shell = getRootShell() + + val cmd = "grep 'multi_user_scan=' /data/misc/user_uid/uid_scanner.conf | cut -d'=' -f2" + val result = ShellUtils.fastCmd(shell, cmd).trim() + + return try { + result.toInt() == 1 + } catch (_: NumberFormatException) { + false + } +}