diff --git a/kernel/Makefile b/kernel/Makefile index 65477f94..4a94d76b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,14 +1,10 @@ kernelsu-objs := ksu.o kernelsu-objs += allowlist.o -kernelsu-objs += dynamic_manager.o -kernelsu-objs += apk_sign.o kernelsu-objs += sucompat.o -kernelsu-objs += throne_tracker.o kernelsu-objs += core_hook.o kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o -kernelsu-objs += throne_comm.o kernelsu-objs += sulog.o ifeq ($(CONFIG_KSU_MANUAL_SU), y) kernelsu-objs += manual_su.o @@ -87,24 +83,6 @@ endif ccflags-y += -DKSU_VERSION=$(KSU_VERSION) ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\" -# Custom Signs -ifdef KSU_EXPECTED_SIZE -ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE) -$(info -- Custom KernelSU Manager signature size: $(KSU_EXPECTED_SIZE)) -endif - -ifdef KSU_EXPECTED_HASH -ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\" -$(info -- Custom KernelSU Manager signature hash: $(KSU_EXPECTED_HASH)) -endif - -ifdef KSU_MANAGER_PACKAGE -ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\" -$(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE)) -endif - -$(info -- Supported Unofficial Manager: 5ec1cff (GKI) ShirkNeko udochina (GKI and KPM)) - ifeq ($(CONFIG_KSU_KPROBES_HOOK), y) $(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK) else ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c deleted file mode 100644 index 2e554580..00000000 --- a/kernel/apk_sign.c +++ /dev/null @@ -1,419 +0,0 @@ -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KSU_DEBUG -#include -#endif -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) -#include -#else -#include -#endif - -#include "apk_sign.h" -#include "dynamic_manager.h" -#include "klog.h" // IWYU pragma: keep -#include "kernel_compat.h" -#include "manager_sign.h" - -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static apk_sign_key_t apk_sign_keys[] = { - {EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // ShirkNeko/SukiSU -#ifdef EXPECTED_SIZE - {EXPECTED_SIZE, EXPECTED_HASH}, // Custom -#endif -}; - -static struct sdesc *init_sdesc(struct crypto_shash *alg) -{ - struct sdesc *sdesc; - int size; - - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - return sdesc; -} - -static int calc_hash(struct crypto_shash *alg, const unsigned char *data, - unsigned int datalen, unsigned char *digest) -{ - struct sdesc *sdesc; - int ret; - - sdesc = init_sdesc(alg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc sdesc\n"); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); - kfree(sdesc); - return ret; -} - -static int ksu_sha256(const unsigned char *data, unsigned int datalen, - unsigned char *digest) -{ - struct crypto_shash *alg; - char *hash_alg_name = "sha256"; - int ret; - - alg = crypto_alloc_shash(hash_alg_name, 0, 0); - if (IS_ERR(alg)) { - pr_info("can't alloc alg %s\n", hash_alg_name); - return PTR_ERR(alg); - } - ret = calc_hash(alg, data, datalen, digest); - crypto_free_shash(alg); - 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; - - 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 (size4 != current_dynamic_key.size) { - return false; - } - -#define CERT_MAX_LENGTH 1024 - char cert[CERT_MAX_LENGTH]; - if (size4 > CERT_MAX_LENGTH) { - pr_info("cert length overlimit\n"); - return false; - } - - ksu_kernel_read_compat(fp, cert, size4, pos); - - unsigned char digest[SHA256_DIGEST_SIZE]; - if (ksu_sha256(cert, size4, digest) < 0) { - pr_info("sha256 error\n"); - return false; - } - - char hash_str[SHA256_DIGEST_SIZE * 2 + 1]; - hash_str[SHA256_DIGEST_SIZE * 2] = '\0'; - bin2hex(hash_str, digest, SHA256_DIGEST_SIZE); - - 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 (matched_index) { - *matched_index = DYNAMIC_SIGN_INDEX; - } - return true; - } - - return false; -} - -static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, int *matched_index) -{ - int i; - apk_sign_key_t sign_key; - bool signature_valid = false; - - ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length - ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length - ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length - - *offset += 0x4 * 3; - - ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length - - *pos += *size4; - *offset += 0x4 + *size4; - - ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length - ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length - *offset += 0x4 * 2; - - if (ksu_is_dynamic_manager_enabled()) { - loff_t temp_pos = *pos; - if (check_dynamic_sign(fp, *size4, &temp_pos, matched_index)) { - *pos = temp_pos; - *offset += *size4; - return true; - } - } - - for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) { - sign_key = apk_sign_keys[i]; - - if (*size4 != sign_key.size) - continue; - *offset += *size4; - -#define CERT_MAX_LENGTH 1024 - char cert[CERT_MAX_LENGTH]; - if (*size4 > CERT_MAX_LENGTH) { - pr_info("cert length overlimit\n"); - return false; - } - ksu_kernel_read_compat(fp, cert, *size4, pos); - unsigned char digest[SHA256_DIGEST_SIZE]; - if (IS_ERR(ksu_sha256(cert, *size4, digest))) { - pr_info("sha256 error\n"); - return false; - } - - char hash_str[SHA256_DIGEST_SIZE * 2 + 1]; - hash_str[SHA256_DIGEST_SIZE * 2] = '\0'; - - bin2hex(hash_str, digest, SHA256_DIGEST_SIZE); - pr_info("sha256: %s, expected: %s, index: %d\n", hash_str, sign_key.sha256, i); - - if (strcmp(sign_key.sha256, hash_str) == 0) { - signature_valid = true; - if (matched_index) { - *matched_index = i; - } - break; - } - } - return signature_valid; -} - -struct zip_entry_header { - uint32_t signature; - uint16_t version; - uint16_t flags; - uint16_t compression; - uint16_t mod_time; - uint16_t mod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t file_name_length; - uint16_t extra_field_length; -} __attribute__((packed)); - -// This is a necessary but not sufficient condition, but it is enough for us -static bool has_v1_signature_file(struct file *fp) -{ - struct zip_entry_header header; - const char MANIFEST[] = "META-INF/MANIFEST.MF"; - - loff_t pos = 0; - - while (ksu_kernel_read_compat(fp, &header, - sizeof(struct zip_entry_header), &pos) == - sizeof(struct zip_entry_header)) { - if (header.signature != 0x04034b50) { - // ZIP magic: 'PK' - return false; - } - // Read the entry file name - if (header.file_name_length == sizeof(MANIFEST) - 1) { - char fileName[sizeof(MANIFEST)]; - ksu_kernel_read_compat(fp, fileName, - header.file_name_length, &pos); - fileName[header.file_name_length] = '\0'; - - // Check if the entry matches META-INF/MANIFEST.MF - if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) == 0) { - return true; - } - } else { - // Skip the entry file name - pos += header.file_name_length; - } - - // Skip to the next entry - pos += header.extra_field_length + header.compressed_size; - } - - return false; -} - -static __always_inline bool check_v2_signature(char *path, bool check_multi_manager, int *signature_index) -{ - unsigned char buffer[0x11] = { 0 }; - u32 size4; - u64 size8, size_of_block; - loff_t pos; - bool v2_signing_valid = false; - int v2_signing_blocks = 0; - bool v3_signing_exist = false; - bool v3_1_signing_exist = false; - int matched_index = -1; - int i; - struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_err("open %s error.\n", path); - return false; - } - - // If you want to check for multi-manager APK signing, but dynamic managering is not enabled, skip - if (check_multi_manager && !ksu_is_dynamic_manager_enabled()) { - filp_close(fp, 0); - return 0; - } - - // disable inotify for this file - fp->f_mode |= FMODE_NONOTIFY; - - // https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD) - for (i = 0;; ++i) { - unsigned short n; - pos = generic_file_llseek(fp, -i - 2, SEEK_END); - ksu_kernel_read_compat(fp, &n, 2, &pos); - if (n == i) { - pos -= 22; - ksu_kernel_read_compat(fp, &size4, 4, &pos); - if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) { - break; - } - } - if (i == 0xffff) { - pr_info("error: cannot find eocd\n"); - goto clean; - } - } - - pos += 12; - // offset - ksu_kernel_read_compat(fp, &size4, 0x4, &pos); - pos = size4 - 0x18; - - ksu_kernel_read_compat(fp, &size8, 0x8, &pos); - ksu_kernel_read_compat(fp, buffer, 0x10, &pos); - if (strcmp((char *)buffer, "APK Sig Block 42")) { - goto clean; - } - - pos = size4 - (size8 + 0x8); - ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos); - if (size_of_block != size8) { - goto clean; - } - - int loop_count = 0; - while (loop_count++ < 10) { - uint32_t id; - uint32_t offset; - ksu_kernel_read_compat(fp, &size8, 0x8, - &pos); // sequence length - if (size8 == size_of_block) { - break; - } - ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id - offset = 4; - if (id == 0x7109871au) { - v2_signing_blocks++; - bool result = check_block(fp, &size4, &pos, &offset, &matched_index); - if (result) { - v2_signing_valid = true; - } - } else if (id == 0xf05368c0u) { - // http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#73 - v3_signing_exist = true; - } else if (id == 0x1b93ad61u) { - // http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#74 - v3_1_signing_exist = true; - } else { -#ifdef CONFIG_KSU_DEBUG - pr_info("Unknown id: 0x%08x\n", id); -#endif - } - pos += (size8 - offset); - } - - if (v2_signing_blocks != 1) { -#ifdef CONFIG_KSU_DEBUG - pr_err("Unexpected v2 signature count: %d\n", - v2_signing_blocks); -#endif - v2_signing_valid = false; - } - - if (v2_signing_valid) { - int has_v1_signing = has_v1_signature_file(fp); - if (has_v1_signing) { - pr_err("Unexpected v1 signature scheme found!\n"); - filp_close(fp, 0); - return false; - } - } -clean: - filp_close(fp, 0); - - if (v3_signing_exist || v3_1_signing_exist) { -#ifdef CONFIG_KSU_DEBUG - pr_err("Unexpected v3 signature scheme found!\n"); -#endif - return false; - } - - if (v2_signing_valid) { - if (signature_index) { - *signature_index = matched_index; - } - - 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); - return true; - } - return false; - } else { - // Common manager check: any valid signature will do - return true; - } - } - return false; -} - -#ifdef CONFIG_KSU_DEBUG - -int ksu_debug_manager_uid = -1; - -#include "manager.h" - -static int set_expected_size(const char *val, const struct kernel_param *kp) -{ - int rv = param_set_uint(val, kp); - ksu_set_manager_uid(ksu_debug_manager_uid); - pr_info("ksu_manager_uid set to %d\n", ksu_debug_manager_uid); - return rv; -} - -static struct kernel_param_ops expected_size_ops = { - .set = set_expected_size, - .get = param_get_uint, -}; - -module_param_cb(ksu_debug_manager_uid, &expected_size_ops, - &ksu_debug_manager_uid, S_IRUSR | S_IWUSR); - -#endif - -bool is_manager_apk(char *path) -{ - return check_v2_signature(path, false, NULL); -} - -bool is_dynamic_manager_apk(char *path, int *signature_index) -{ - return check_v2_signature(path, true, signature_index); -} \ No newline at end of file diff --git a/kernel/apk_sign.h b/kernel/apk_sign.h deleted file mode 100644 index 06c44616..00000000 --- a/kernel/apk_sign.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __KSU_H_APK_V2_SIGN -#define __KSU_H_APK_V2_SIGN - -#include -#include "ksu.h" - -bool is_manager_apk(char *path); - -bool is_dynamic_manager_apk(char *path, int *signature_index); - -#endif diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 0f704b09..d5ce75d0 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -43,10 +43,7 @@ #include "ksud.h" #include "manager.h" #include "selinux/selinux.h" -#include "throne_tracker.h" -#include "throne_comm.h" #include "kernel_compat.h" -#include "dynamic_manager.h" #include "sulog.h" #ifdef CONFIG_KSU_MANUAL_SU @@ -318,48 +315,6 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) } #endif -int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) -{ - if (!current->mm) { - // skip kernel threads - return 0; - } - - if (current_uid().val != 1000) { - // skip non system uid - return 0; - } - - if (!old_dentry || !new_dentry) { - return 0; - } - - // /data/system/packages.list.tmp -> /data/system/packages.list - if (strcmp(new_dentry->d_iname, "packages.list")) { - return 0; - } - - char path[128]; - char *buf = dentry_path_raw(new_dentry, path, sizeof(path)); - if (IS_ERR(buf)) { - pr_err("dentry_path_raw failed.\n"); - return 0; - } - - if (!strstr(buf, "/system/packages.list")) { - return 0; - } - 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(); - - return 0; -} #ifdef CONFIG_EXT4_FS static void nuke_ext4_sysfs() { @@ -459,48 +414,21 @@ static void sulog_prctl_cmd(uid_t uid, unsigned long cmd) int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - // if success, we modify the arg5 as result! - bool is_manual_su_cmd = false; u32 *result = (u32 *)arg5; u32 reply_ok = KERNEL_SU_OPTION; - uid_t current_uid_val = current_uid().val; -#ifdef CONFIG_KSU_MANUAL_SU - is_manual_su_cmd = (arg2 == CMD_SU_ESCALATION_REQUEST || - arg2 == CMD_ADD_PENDING_ROOT); -#endif - - // skip this private space support if uid below 100k - if (current_uid_val < 100000) - goto skip_check; - - uid_t manager_uid = ksu_get_manager_uid(); - if (current_uid_val != manager_uid && - current_uid_val % 100000 == manager_uid) { - ksu_set_manager_uid(current_uid_val); - } - -skip_check: - // yes this causes delay, but this keeps the delay consistent, which is what we want - // with a barrier for safety as the compiler might try to do something smart. - DONT_GET_SMART(); - if (!is_allow_su() && !is_system_uid()) - return 0; - - // we move it after uid check here so they cannot - // compare 0xdeadbeef call to a non-0xdeadbeef call if (KERNEL_SU_OPTION != option) return 0; - // just continue old logic bool from_root = !current_uid().val; + bool from_daemon = is_daemon(); bool from_manager = is_manager(); + bool from_system_uid = is_system_uid(); + bool from_system_bin_su = is_system_bin_su(); sulog_prctl_cmd(current_uid().val, arg2); - if (!from_root && !from_manager - && !(is_manual_su_cmd ? is_system_uid(): - (is_allow_su() && is_system_bin_su()))) { + if (!from_root && !from_daemon && !from_manager && !from_system_uid && !from_system_bin_su) { // only root or manager can access this interface return 0; } @@ -510,12 +438,39 @@ skip_check: #endif if (arg2 == CMD_BECOME_MANAGER) { - if (from_manager) { + // Manager app verifies its identity + if (ksu_is_manager_uid_valid() && + ksu_get_manager_uid() == current_uid().val) { if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { pr_err("become_manager: prctl reply error\n"); } + } + return 0; + } + + if (arg2 == CMD_BECOME_DAEMON) { + // Only root can become daemon (ksud daemon runs as root) + if (!from_root) { + pr_err("become_daemon: not from root\n"); return 0; } + + char token[65]; + if (copy_from_user(token, (void __user *)arg3, 65)) { + pr_err("become_daemon: copy token failed\n"); + return 0; + } + token[64] = '\0'; + + if (ksu_verify_daemon_token(token)) { + ksu_set_daemon_pid(current->pid); + pr_info("ksud daemon registered, pid: %d\n", current->pid); + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("become_daemon: prctl reply error\n"); + } + } else { + pr_err("become_daemon: invalid token\n"); + } return 0; } @@ -628,10 +583,6 @@ skip_check: pr_info("post-fs-data triggered\n"); on_post_fs_data(); ksu_sulog_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"); } break; @@ -745,6 +696,28 @@ skip_check: return 0; } + if (arg2 == CMD_SET_MANAGER_UID) { + // Only daemon can set manager uid + if (!from_daemon) { + pr_err("set_manager_uid: not daemon\n"); + return 0; + } + + uid_t uid; + if (copy_from_user(&uid, (void __user *)arg3, sizeof(uid))) { + pr_err("set_manager_uid: copy uid failed\n"); + return 0; + } + + ksu_set_manager_uid(uid); + pr_info("manager uid set to %d\n", uid); + + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("prctl reply error, cmd: %lu\n", arg2); + } + return 0; + } + #ifdef CONFIG_KPM // ADD: 添加KPM模块控制 if(sukisu_is_kpm_control_code(arg2)) { @@ -827,9 +800,8 @@ skip_check: } #endif - - // all other cmds are for 'root manager' - if (!from_manager) { + // all other cmds are for 'daemon or manager' + if (!from_daemon && !from_manager) { return 0; } @@ -1087,26 +1059,6 @@ static struct kprobe prctl_kp = { .pre_handler = handler_pre, }; -static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) - // https://elixir.bootlin.com/linux/v5.12-rc1/source/include/linux/fs.h - struct renamedata *rd = PT_REGS_PARM1(regs); - struct dentry *old_entry = rd->old_dentry; - struct dentry *new_entry = rd->new_dentry; -#else - struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs); - struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs); -#endif - - return ksu_handle_rename(old_entry, new_entry); -} - -static struct kprobe renameat_kp = { - .symbol_name = "vfs_rename", - .pre_handler = renameat_handler_pre, -}; - __maybe_unused int ksu_kprobe_init(void) { int rc = 0; @@ -1117,16 +1069,12 @@ __maybe_unused int ksu_kprobe_init(void) return rc; } - rc = register_kprobe(&renameat_kp); - pr_info("renameat kp: %d\n", rc); - return rc; } __maybe_unused int ksu_kprobe_exit(void) { unregister_kprobe(&prctl_kp); - unregister_kprobe(&renameat_kp); return 0; } @@ -1206,12 +1154,6 @@ static int ksu_task_alloc(struct task_struct *task, } #endif -static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) -{ - return ksu_handle_rename(old_dentry, new_dentry); -} - static int ksu_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { @@ -1221,7 +1163,6 @@ static int ksu_task_fix_setuid(struct cred *new, const struct cred *old, #ifndef MODULE static struct security_hook_list ksu_hooks[] = { LSM_HOOK_INIT(task_prctl, ksu_task_prctl), - LSM_HOOK_INIT(inode_rename, ksu_inode_rename), LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid), LSM_HOOK_INIT(inode_permission, ksu_inode_permission), #ifdef CONFIG_KSU_MANUAL_SU @@ -1386,26 +1327,6 @@ void __init ksu_lsm_hook_init(void) } else { pr_warn("Failed to find task_prctl!\n"); } - - int inode_killpriv_index = -1; - void *cap_killpriv = GET_SYMBOL_ADDR(cap_inode_killpriv); - find_head_addr(cap_killpriv, &inode_killpriv_index); - if (inode_killpriv_index < 0) { - pr_warn("Failed to find inode_rename, use kprobe instead!\n"); - register_kprobe(&renameat_kp); - } else { - int inode_rename_index = inode_killpriv_index + - &security_hook_heads.inode_rename - - &security_hook_heads.inode_killpriv; - struct hlist_head *head_start = - (struct hlist_head *)&security_hook_heads; - void *inode_rename_head = head_start + inode_rename_index; - if (inode_rename_head != &security_hook_heads.inode_rename) { - pr_warn("inode_rename's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(inode_rename_head, inode_rename, - ksu_inode_rename); - } void *cap_setuid = GET_SYMBOL_ADDR(cap_task_fix_setuid); void *setuid_head = find_head_addr(cap_setuid, NULL); if (setuid_head) { @@ -1428,8 +1349,6 @@ void __init ksu_core_init(void) void ksu_core_exit(void) { - ksu_uid_exit(); - ksu_throne_comm_exit(); ksu_sulog_exit(); #ifdef CONFIG_KPROBE pr_info("ksu_core_kprobe_exit\n"); diff --git a/kernel/dynamic_manager.c b/kernel/dynamic_manager.c deleted file mode 100644 index 6f34d192..00000000 --- a/kernel/dynamic_manager.c +++ /dev/null @@ -1,505 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KSU_DEBUG -#include -#endif -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) -#include -#else -#include -#endif - -#include "dynamic_manager.h" -#include "klog.h" // IWYU pragma: keep -#include "kernel_compat.h" -#include "manager.h" - -#define MAX_MANAGERS 2 - -// Dynamic sign configuration -static struct dynamic_manager_config dynamic_manager = { - .size = 0x300, - .hash = "0000000000000000000000000000000000000000000000000000000000000000", - .is_set = 0 -}; - -// Multi-manager state -static struct manager_info active_managers[MAX_MANAGERS]; -static DEFINE_SPINLOCK(managers_lock); -static DEFINE_SPINLOCK(dynamic_manager_lock); - -// Work queues for persistent storage -static struct work_struct save_dynamic_manager_work; -static struct work_struct load_dynamic_manager_work; -static struct work_struct clear_dynamic_manager_work; - -bool ksu_is_dynamic_manager_enabled(void) -{ - unsigned long flags; - bool enabled; - - spin_lock_irqsave(&dynamic_manager_lock, flags); - enabled = dynamic_manager.is_set; - spin_unlock_irqrestore(&dynamic_manager_lock, flags); - - return enabled; -} - -void ksu_add_manager(uid_t uid, int signature_index) -{ - unsigned long flags; - int i; - - if (!ksu_is_dynamic_manager_enabled()) { - pr_info("Dynamic sign not enabled, skipping multi-manager add\n"); - return; - } - - spin_lock_irqsave(&managers_lock, flags); - - // Check if manager already exists and update - for (i = 0; i < MAX_MANAGERS; i++) { - 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); - return; - } - } - - // Find free slot for new manager - for (i = 0; i < MAX_MANAGERS; i++) { - if (!active_managers[i].is_active) { - active_managers[i].uid = uid; - 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); - return; - } - } - - spin_unlock_irqrestore(&managers_lock, flags); - pr_warn("Failed to add manager, no free slots\n"); -} - -void ksu_remove_manager(uid_t uid) -{ - unsigned long flags; - int i; - - if (!ksu_is_dynamic_manager_enabled()) { - return; - } - - spin_lock_irqsave(&managers_lock, flags); - - 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); - break; - } - } - - spin_unlock_irqrestore(&managers_lock, flags); -} - -bool ksu_is_any_manager(uid_t uid) -{ - unsigned long flags; - bool is_manager = 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 && active_managers[i].uid == uid) { - is_manager = true; - break; - } - } - - spin_unlock_irqrestore(&managers_lock, flags); - return is_manager; -} - -int ksu_get_manager_signature_index(uid_t uid) -{ - unsigned long flags; - int signature_index = -1; - int i; - - // Check traditional manager first - if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) { - return DYNAMIC_SIGN_INDEX; - } - - if (!ksu_is_dynamic_manager_enabled()) { - return -1; - } - - spin_lock_irqsave(&managers_lock, flags); - - for (i = 0; i < MAX_MANAGERS; i++) { - if (active_managers[i].is_active && active_managers[i].uid == uid) { - signature_index = active_managers[i].signature_index; - break; - } - } - - spin_unlock_irqrestore(&managers_lock, flags); - return signature_index; -} - -static void clear_dynamic_manager(void) -{ - unsigned long flags; - int i; - - 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); - active_managers[i].is_active = false; - } - } - - spin_unlock_irqrestore(&managers_lock, flags); -} - -int ksu_get_active_managers(struct manager_list_info *info) -{ - 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; -} - -static void do_save_dynamic_manager(struct work_struct *work) -{ - u32 magic = DYNAMIC_MANAGER_FILE_MAGIC; - u32 version = DYNAMIC_MANAGER_FILE_VERSION; - struct dynamic_manager_config config_to_save; - loff_t off = 0; - unsigned long flags; - struct file *fp; - - spin_lock_irqsave(&dynamic_manager_lock, flags); - config_to_save = dynamic_manager; - 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)); - 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, &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); -} - -static void do_load_dynamic_manager(struct work_struct *work) -{ - loff_t off = 0; - ssize_t ret = 0; - struct file *fp = NULL; - u32 magic; - u32 version; - struct dynamic_manager_config loaded_config; - unsigned long flags; - int i; - - 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)); - } - 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); - goto exit; - } - - if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != sizeof(version)) { - pr_err("dynamic manager 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)); - goto exit; - } - - if (loaded_config.size < 0x100 || loaded_config.size > 0x1000) { - pr_err("Invalid saved config 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)); - goto exit; - } - - // Validate hash format - 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); - goto exit; - } - } - - spin_lock_irqsave(&dynamic_manager_lock, flags); - dynamic_manager = loaded_config; - spin_unlock_irqrestore(&dynamic_manager_lock, flags); - - pr_info("Dynamic sign config loaded: size=0x%x, hash=%.16s...\n", - loaded_config.size, loaded_config.hash); - -exit: - filp_close(fp, 0); -} - -static bool persistent_dynamic_manager(void) -{ - return ksu_queue_work(&save_dynamic_manager_work); -} - -static void do_clear_dynamic_manager(struct work_struct *work) -{ - loff_t off = 0; - struct file *fp; - char zero_buffer[512]; - - memset(zero_buffer, 0, sizeof(zero_buffer)); - - 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)); - 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"); - } - - filp_close(fp, 0); -} - -static bool clear_dynamic_manager_file(void) -{ - return ksu_queue_work(&clear_dynamic_manager_work); -} - -int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config) -{ - unsigned long flags; - int ret = 0; - int i; - - if (!config) { - return -EINVAL; - } - - switch (config->operation) { - case DYNAMIC_MANAGER_OP_SET: - if (config->size < 0x100 || config->size > 0x1000) { - pr_err("invalid size: 0x%x\n", config->size); - return -EINVAL; - } - - if (strlen(config->hash) != 64) { - pr_err("invalid hash length: %zu\n", strlen(config->hash)); - return -EINVAL; - } - - // Validate hash format - 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); - return -EINVAL; - } - } - - spin_lock_irqsave(&dynamic_manager_lock, flags); - dynamic_manager.size = config->size; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(dynamic_manager.hash, config->hash, sizeof(dynamic_manager.hash)); -#else - strlcpy(dynamic_manager.hash, config->hash, sizeof(dynamic_manager.hash)); -#endif - dynamic_manager.is_set = 1; - spin_unlock_irqrestore(&dynamic_manager_lock, flags); - - persistent_dynamic_manager(); - pr_info("dynamic manager updated: size=0x%x, hash=%.16s... (multi-manager enabled)\n", - config->size, config->hash); - break; - - case DYNAMIC_MANAGER_OP_GET: - spin_lock_irqsave(&dynamic_manager_lock, flags); - if (dynamic_manager.is_set) { - config->size = dynamic_manager.size; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(config->hash, dynamic_manager.hash, sizeof(config->hash)); -#else - strlcpy(config->hash, dynamic_manager.hash, sizeof(config->hash)); -#endif - ret = 0; - } else { - ret = -ENODATA; - } - spin_unlock_irqrestore(&dynamic_manager_lock, flags); - break; - - case DYNAMIC_MANAGER_OP_CLEAR: - spin_lock_irqsave(&dynamic_manager_lock, flags); - dynamic_manager.size = 0x300; - strcpy(dynamic_manager.hash, "0000000000000000000000000000000000000000000000000000000000000000"); - 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_dynamic_manager_file(); - - pr_info("Dynamic sign config cleared (multi-manager disabled)\n"); - break; - - default: - pr_err("Invalid dynamic manager operation: %d\n", config->operation); - return -EINVAL; - } - - return ret; -} - -bool ksu_load_dynamic_manager(void) -{ - return ksu_queue_work(&load_dynamic_manager_work); -} - -void ksu_dynamic_manager_init(void) -{ - int i; - - INIT_WORK(&save_dynamic_manager_work, do_save_dynamic_manager); - INIT_WORK(&load_dynamic_manager_work, do_load_dynamic_manager); - INIT_WORK(&clear_dynamic_manager_work, do_clear_dynamic_manager); - - // Initialize manager slots - for (i = 0; i < MAX_MANAGERS; i++) { - active_managers[i].is_active = false; - } - - ksu_load_dynamic_manager(); - - pr_info("Dynamic sign initialized with conditional multi-manager support\n"); -} - -void ksu_dynamic_manager_exit(void) -{ - clear_dynamic_manager(); - - // Save current config before exit - do_save_dynamic_manager(NULL); - pr_info("Dynamic sign exited with persistent storage\n"); -} - -// Get dynamic manager configuration for signature verification -bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash) -{ - unsigned long flags; - bool valid = false; - - spin_lock_irqsave(&dynamic_manager_lock, flags); - if (dynamic_manager.is_set) { - if (size) *size = dynamic_manager.size; - if (hash) *hash = dynamic_manager.hash; - valid = true; - } - spin_unlock_irqrestore(&dynamic_manager_lock, flags); - - return valid; -} \ No newline at end of file diff --git a/kernel/dynamic_manager.h b/kernel/dynamic_manager.h deleted file mode 100644 index 1b5a5cbd..00000000 --- a/kernel/dynamic_manager.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __KSU_H_DYNAMIC_MANAGER -#define __KSU_H_DYNAMIC_MANAGER - -#include -#include "ksu.h" - -#define DYNAMIC_MANAGER_FILE_MAGIC 0x7f445347 // 'DSG', u32 -#define DYNAMIC_MANAGER_FILE_VERSION 1 // u32 -#define KERNEL_SU_DYNAMIC_MANAGER "/data/adb/ksu/.dynamic_manager" -#define DYNAMIC_SIGN_INDEX 100 - -struct dynamic_sign_key { - unsigned int size; - const char *hash; -}; - -#define DYNAMIC_SIGN_DEFAULT_CONFIG { \ - .size = 0x300, \ - .hash = "0000000000000000000000000000000000000000000000000000000000000000" \ -} - -struct dynamic_manager_config { - unsigned int size; - char hash[65]; - int is_set; -}; - -struct manager_info { - uid_t uid; - int signature_index; - 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 -bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash); - -#endif \ No newline at end of file diff --git a/kernel/ksu.c b/kernel/ksu.c index d4c87df4..4fcc2e41 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -10,7 +10,7 @@ #include "core_hook.h" #include "klog.h" // IWYU pragma: keep #include "ksu.h" -#include "throne_tracker.h" +#include "manager.h" static struct workqueue_struct *ksu_workqueue; @@ -45,11 +45,15 @@ int __init kernelsu_init(void) ksu_core_init(); - ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0); + ksu_generate_daemon_token(); +#ifdef CONFIG_KSU_DEBUG + pr_info("Daemon token: %s\n", ksu_get_daemon_token()); +#endif + + ksu_throne_tracker_init = alloc_ordered_workqueue("kernelsu_work_queue", 0); ksu_allowlist_init(); - ksu_throne_tracker_init(); #ifdef CONFIG_KSU_KPROBES_HOOK ksu_sucompat_init(); ksu_ksud_init(); @@ -73,8 +77,6 @@ void kernelsu_exit(void) { ksu_allowlist_exit(); - ksu_throne_tracker_exit(); - destroy_workqueue(ksu_workqueue); #ifdef CONFIG_KSU_KPROBES_HOOK diff --git a/kernel/ksu.h b/kernel/ksu.h index 1c6780a3..71a636b6 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -23,6 +23,8 @@ #define CMD_UID_SHOULD_UMOUNT 13 #define CMD_IS_SU_ENABLED 14 #define CMD_ENABLE_SU 15 +#define CMD_BECOME_DAEMON 17 +#define CMD_SET_MANAGER_UID 18 #ifdef CONFIG_KSU_MANUAL_SU #define CMD_SU_ESCALATION_REQUEST 50 diff --git a/kernel/ksud.c b/kernel/ksud.c index f121b623..fd9676fb 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -17,9 +18,39 @@ #include "arch.h" #include "klog.h" // IWYU pragma: keep #include "ksud.h" +#include "manager.h" #include "kernel_compat.h" #include "selinux/selinux.h" +// Daemon token implementation +pid_t ksu_daemon_pid = KSU_INVALID_PID; +char ksu_daemon_token[65] = {0}; + +void ksu_generate_daemon_token(void) +{ + unsigned char random_bytes[32]; + get_random_bytes(random_bytes, 32); + bin2hex(ksu_daemon_token, random_bytes, 32); + ksu_daemon_token[64] = '\0'; + pr_info("KernelSU daemon token generated\n"); +} + +const char* ksu_get_daemon_token(void) +{ + return ksu_daemon_token; +} + +bool ksu_verify_daemon_token(const char *token) +{ + if (!token || strlen(token) != 64) { + return false; + } + return strncmp(ksu_daemon_token, token, 64) == 0; +} + +// Manager UID implementation +uid_t ksu_manager_uid = KSU_INVALID_UID; + static const char KERNEL_SU_RC[] = "\n" @@ -42,6 +73,11 @@ static const char KERNEL_SU_RC[] = " exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n" "\n" + "on property:sys.boot_completed=1\n" + " setenv KSUD_DAEMON_TOKEN __KSU_DAEMON_TOKEN_PLACEHOLDER__\n" + " exec u:r:su:s0 root -- " KSUD_PATH " daemon\n" + "\n" + "\n"; static void stop_vfs_read_hook(); @@ -319,7 +355,23 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, buf = *buf_ptr; count = *count_ptr; - size_t rc_count = strlen(KERNEL_SU_RC); + // Prepare RC content with token replacement + char rc_with_token[sizeof(KERNEL_SU_RC) + 64]; + const char *token = ksu_get_daemon_token(); + const char *placeholder = "__KSU_DAEMON_TOKEN_PLACEHOLDER__"; + const char *token_pos = strstr(KERNEL_SU_RC, placeholder); + + if (token_pos) { + size_t prefix_len = token_pos - KERNEL_SU_RC; + memcpy(rc_with_token, KERNEL_SU_RC, prefix_len); + memcpy(rc_with_token + prefix_len, token, 64); + strcpy(rc_with_token + prefix_len + 64, token_pos + strlen(placeholder)); + } else { + pr_err("Token placeholder not found in RC!\n"); + strcpy(rc_with_token, KERNEL_SU_RC); + } + + size_t rc_count = strlen(rc_with_token); pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath, current->comm, count, rc_count); @@ -329,7 +381,7 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, return 0; } - size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count); + size_t ret = copy_to_user(buf, rc_with_token, rc_count); if (ret) { pr_err("copy ksud.rc failed: %zu\n", ret); return 0; diff --git a/kernel/manager.h b/kernel/manager.h index f27afbbf..7a141855 100644 --- a/kernel/manager.h +++ b/kernel/manager.h @@ -4,27 +4,56 @@ #include #include +#define KSU_INVALID_PID -1 #define KSU_INVALID_UID -1 -extern uid_t ksu_manager_uid; // DO NOT DIRECT USE +// Daemon (ksud) - identified by PID + token +extern pid_t ksu_daemon_pid; +extern char ksu_daemon_token[65]; -extern bool ksu_is_any_manager(uid_t uid); -extern void ksu_add_manager(uid_t uid, int signature_index); -extern void ksu_remove_manager(uid_t uid); -extern int ksu_get_manager_signature_index(uid_t uid); +static inline bool ksu_is_daemon_pid_valid(void) +{ + return ksu_daemon_pid != KSU_INVALID_PID; +} -static inline bool ksu_is_manager_uid_valid() +static inline bool is_daemon(void) +{ + return unlikely(ksu_daemon_pid == current->pid); +} + +static inline pid_t ksu_get_daemon_pid(void) +{ + return ksu_daemon_pid; +} + +static inline void ksu_set_daemon_pid(pid_t pid) +{ + ksu_daemon_pid = pid; +} + +static inline void ksu_invalidate_daemon_pid(void) +{ + ksu_daemon_pid = KSU_INVALID_PID; +} + +void ksu_generate_daemon_token(void); +const char* ksu_get_daemon_token(void); +bool ksu_verify_daemon_token(const char *token); + +// Manager (app) - identified by UID +extern uid_t ksu_manager_uid; + +static inline bool ksu_is_manager_uid_valid(void) { return ksu_manager_uid != KSU_INVALID_UID; } -static inline bool is_manager() +static inline bool is_manager(void) { - return unlikely(ksu_is_any_manager(current_uid().val) || - (ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val)); + return unlikely(ksu_manager_uid == current_uid().val); } -static inline uid_t ksu_get_manager_uid() +static inline uid_t ksu_get_manager_uid(void) { return ksu_manager_uid; } @@ -34,7 +63,7 @@ static inline void ksu_set_manager_uid(uid_t uid) ksu_manager_uid = uid; } -static inline void ksu_invalidate_manager_uid() +static inline void ksu_invalidate_manager_uid(void) { ksu_manager_uid = KSU_INVALID_UID; } diff --git a/kernel/manager_sign.h b/kernel/manager_sign.h deleted file mode 100644 index 7de89937..00000000 --- a/kernel/manager_sign.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MANAGER_SIGN_H -#define MANAGER_SIGN_H - -// ShirkNeko/SukiSU -#define EXPECTED_SIZE_SHIRKNEKO 0x35c -#define EXPECTED_HASH_SHIRKNEKO "947ae944f3de4ed4c21a7e4f7953ecf351bfa2b36239da37a34111ad29993eef" - -// Dynamic Sign -#define EXPECTED_SIZE_OTHER 0x300 -#define EXPECTED_HASH_OTHER "0000000000000000000000000000000000000000000000000000000000000000" - -typedef struct { - unsigned size; - const char *sha256; -} apk_sign_key_t; - -#endif /* MANAGER_SIGN_H */ diff --git a/kernel/throne_comm.c b/kernel/throne_comm.c deleted file mode 100644 index 79acb6bd..00000000 --- a/kernel/throne_comm.c +++ /dev/null @@ -1,204 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#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; - -static void rescan_work_fn(struct work_struct *work) -{ - // Signal userspace through proc interface - need_rescan = true; - pr_info("requested userspace uid rescan\n"); -} - -void ksu_request_userspace_scan(void) -{ - if (scanner_wq) { - queue_work(scanner_wq, &scan_work); - } -} - -void ksu_handle_userspace_update(void) -{ - // Called when userspace notifies update complete - need_rescan = false; - 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) { - seq_puts(m, "RESCAN\n"); - } else { - seq_puts(m, "OK\n"); - } - return 0; -} - -static int uid_scanner_open(struct inode *inode, struct file *file) -{ - return single_open(file, uid_scanner_show, NULL); -} - -static ssize_t uid_scanner_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - char cmd[16]; - - if (count >= sizeof(cmd)) - return -EINVAL; - - if (copy_from_user(cmd, buffer, count)) - return -EFAULT; - - cmd[count] = '\0'; - - // Remove newline if present - if (count > 0 && cmd[count-1] == '\n') - cmd[count-1] = '\0'; - - if (strcmp(cmd, "UPDATED") == 0) { - ksu_handle_userspace_update(); - pr_info("received userspace update notification\n"); - } - - return count; -} - -static const struct proc_ops uid_scanner_proc_ops = { - .proc_open = uid_scanner_open, - .proc_read = seq_read, - .proc_write = uid_scanner_write, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; - -int ksu_throne_comm_init(void) -{ - // Create workqueue - scanner_wq = alloc_workqueue("ksu_scanner", WQ_UNBOUND, 1); - if (!scanner_wq) { - pr_err("failed to create scanner workqueue\n"); - return -ENOMEM; - } - - INIT_WORK(&scan_work, rescan_work_fn); - - // Create proc entry - proc_entry = proc_create(PROC_UID_SCANNER, 0600, NULL, &uid_scanner_proc_ops); - if (!proc_entry) { - pr_err("failed to create proc entry\n"); - destroy_workqueue(scanner_wq); - return -ENOMEM; - } - - pr_info("throne communication initialized\n"); - return 0; -} - -void ksu_throne_comm_exit(void) -{ - if (proc_entry) { - proc_remove(proc_entry); - proc_entry = NULL; - } - - if (scanner_wq) { - destroy_workqueue(scanner_wq); - scanner_wq = NULL; - } - - 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 deleted file mode 100644 index 4deba2ab..00000000 --- a/kernel/throne_comm.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __KSU_H_THRONE_COMM -#define __KSU_H_THRONE_COMM - -void ksu_request_userspace_scan(void); - -void ksu_handle_userspace_update(void); - -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 deleted file mode 100644 index ba5b43de..00000000 --- a/kernel/throne_tracker.c +++ /dev/null @@ -1,647 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "allowlist.h" -#include "klog.h" // IWYU pragma: keep -#include "ksu.h" -#include "manager.h" -#include "throne_tracker.h" -#include "kernel_compat.h" -#include "dynamic_manager.h" -#include "throne_comm.h" - -uid_t ksu_manager_uid = KSU_INVALID_UID; -static uid_t locked_manager_uid = KSU_INVALID_UID; -static uid_t locked_dynamic_manager_uid = KSU_INVALID_UID; - -#define KSU_UID_LIST_PATH "/data/misc/user_uid/uid_list" -#define USER_DATA_PATH "/data/user_de/0" -#define USER_DATA_PATH_LEN 288 - -struct uid_data { - struct list_head list; - u32 uid; - char package[KSU_MAX_PACKAGE_NAME]; -}; - -// Try read /data/misc/user_uid/uid_list -static int uid_from_um_list(struct list_head *uid_list) -{ - struct file *fp; - char *buf = NULL; - loff_t size, pos = 0; - ssize_t nr; - int cnt = 0; - - fp = ksu_filp_open_compat(KSU_UID_LIST_PATH, O_RDONLY, 0); - if (IS_ERR(fp)) - return -ENOENT; - - size = fp->f_inode->i_size; - if (size <= 0) { - filp_close(fp, NULL); - return -ENODATA; - } - - buf = kzalloc(size + 1, GFP_ATOMIC); - if (!buf) { - pr_err("uid_list: OOM %lld B\n", size); - filp_close(fp, NULL); - return -ENOMEM; - } - - nr = ksu_kernel_read_compat(fp, buf, size, &pos); - filp_close(fp, NULL); - if (nr != size) { - pr_err("uid_list: short read %zd/%lld\n", nr, size); - kfree(buf); - return -EIO; - } - buf[size] = '\0'; - - for (char *line = buf, *next; line; line = next) { - next = strchr(line, '\n'); - if (next) *next++ = '\0'; - - while (*line == ' ' || *line == '\t' || *line == '\r') ++line; - if (!*line) continue; - - char *uid_str = strsep(&line, " \t"); - char *pkg = line; - if (!pkg) continue; - while (*pkg == ' ' || *pkg == '\t') ++pkg; - if (!*pkg) continue; - - u32 uid; - if (kstrtou32(uid_str, 10, &uid)) { - pr_warn_once("uid_list: bad uid <%s>\n", uid_str); - continue; - } - - struct uid_data *d = kzalloc(sizeof(*d), GFP_ATOMIC); - if (unlikely(!d)) { - pr_err("uid_list: OOM uid=%u\n", uid); - continue; - } - - d->uid = uid; - strscpy(d->package, pkg, KSU_MAX_PACKAGE_NAME); - list_add_tail(&d->list, uid_list); - ++cnt; - } - - kfree(buf); - pr_info("uid_list: loaded %d entries\n", cnt); - return cnt > 0 ? 0 : -ENODATA; -} - -static int get_pkg_from_apk_path(char *pkg, const char *path) -{ - int len = strlen(path); - if (len >= KSU_MAX_PACKAGE_NAME || len < 1) - return -1; - - const char *last_slash = NULL; - const char *second_last_slash = NULL; - - int i; - for (i = len - 1; i >= 0; i--) { - if (path[i] == '/') { - if (!last_slash) { - last_slash = &path[i]; - } else { - second_last_slash = &path[i]; - break; - } - } - } - - if (!last_slash || !second_last_slash) - return -1; - - const char *last_hyphen = strchr(second_last_slash, '-'); - if (!last_hyphen || last_hyphen > last_slash) - return -1; - - int pkg_len = last_hyphen - second_last_slash - 1; - if (pkg_len >= KSU_MAX_PACKAGE_NAME || pkg_len <= 0) - return -1; - - // Copying the package name - strncpy(pkg, second_last_slash + 1, pkg_len); - pkg[pkg_len] = '\0'; - - return 0; -} - -static void crown_manager(const char *apk, struct list_head *uid_data, int signature_index) -{ - char pkg[KSU_MAX_PACKAGE_NAME]; - if (get_pkg_from_apk_path(pkg, apk) < 0) { - pr_err("Failed to get package name from apk path: %s\n", apk); - return; - } - - pr_info("manager pkg: %s, signature_index: %d\n", pkg, signature_index); - -#ifdef KSU_MANAGER_PACKAGE - // pkg is `/` - if (strncmp(pkg, KSU_MANAGER_PACKAGE, sizeof(KSU_MANAGER_PACKAGE))) { - pr_info("manager package is inconsistent with kernel build: %s\n", - KSU_MANAGER_PACKAGE); - return; - } -#endif - struct uid_data *np; - - list_for_each_entry(np, uid_data, list) { - if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) { - bool is_dynamic = (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2); - - if (is_dynamic) { - if (locked_dynamic_manager_uid != KSU_INVALID_UID && locked_dynamic_manager_uid != np->uid) { - pr_info("Unlocking previous dynamic manager UID: %d\n", locked_dynamic_manager_uid); - ksu_remove_manager(locked_dynamic_manager_uid); - locked_dynamic_manager_uid = KSU_INVALID_UID; - } - } else { - if (locked_manager_uid != KSU_INVALID_UID && locked_manager_uid != np->uid) { - pr_info("Unlocking previous manager UID: %d\n", locked_manager_uid); - ksu_invalidate_manager_uid(); // unlock old one - locked_manager_uid = KSU_INVALID_UID; - } - } - - pr_info("Crowning %s manager: %s (uid=%d, signature_index=%d)\n", - is_dynamic ? "dynamic" : "traditional", pkg, np->uid, signature_index); - - if (is_dynamic) { - ksu_add_manager(np->uid, signature_index); - locked_dynamic_manager_uid = np->uid; - - // If there is no traditional manager, set it to the current UID - if (!ksu_is_manager_uid_valid()) { - ksu_set_manager_uid(np->uid); - locked_manager_uid = np->uid; - } - } else { - ksu_set_manager_uid(np->uid); // throne new UID - locked_manager_uid = np->uid; // store locked UID - } - break; - } - } -} - -#define DATA_PATH_LEN 384 // 384 is enough for /data/app//base.apk - -struct data_path { - char dirpath[DATA_PATH_LEN]; - int depth; - struct list_head list; -}; - -struct apk_path_hash { - unsigned int hash; - bool exists; - struct list_head list; -}; - -static struct list_head apk_path_hash_list = LIST_HEAD_INIT(apk_path_hash_list); - -struct my_dir_context { - struct dir_context ctx; - struct list_head *data_path_list; - char *parent_dir; - void *private_data; - int depth; - int *stop; -}; -// 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. -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) -#define FILLDIR_RETURN_TYPE bool -#define FILLDIR_ACTOR_CONTINUE true -#define FILLDIR_ACTOR_STOP false -#else -#define FILLDIR_RETURN_TYPE int -#define FILLDIR_ACTOR_CONTINUE 0 -#define FILLDIR_ACTOR_STOP -EINVAL -#endif - -struct uid_scan_stats { - size_t total_found; - size_t errors_encountered; -}; - -struct user_data_context { - struct dir_context ctx; - struct list_head *uid_list; - struct uid_scan_stats *stats; -}; - -FILLDIR_RETURN_TYPE user_data_actor(struct dir_context *ctx, const char *name, - int namelen, loff_t off, u64 ino, - unsigned int d_type) -{ - struct user_data_context *my_ctx = - container_of(ctx, struct user_data_context, ctx); - - if (!my_ctx || !my_ctx->uid_list) { - return FILLDIR_ACTOR_STOP; - } - - if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen)) - return FILLDIR_ACTOR_CONTINUE; - - if (d_type != DT_DIR) - return FILLDIR_ACTOR_CONTINUE; - - if (namelen >= KSU_MAX_PACKAGE_NAME) { - pr_warn("Package name too long: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - char package_path[USER_DATA_PATH_LEN]; - if (snprintf(package_path, sizeof(package_path), "%s/%.*s", - USER_DATA_PATH, namelen, name) >= sizeof(package_path)) { - pr_err("Path too long for package: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - struct path path; - int err = kern_path(package_path, LOOKUP_FOLLOW, &path); - if (err) { - pr_debug("Package path lookup failed: %s (err: %d)\n", package_path, err); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - struct kstat stat; - err = vfs_getattr(&path, &stat, STATX_UID, AT_STATX_SYNC_AS_STAT); - path_put(&path); - - if (err) { - pr_info("Failed to get attributes for: %s (err: %d)\n", package_path, err); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - uid_t uid = from_kuid(&init_user_ns, stat.uid); - if (uid == (uid_t)-1) { - pr_warn("Invalid UID for package: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC); - if (!data) { - pr_err("Failed to allocate memory for package: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - data->uid = uid; - size_t copy_len = min(namelen, KSU_MAX_PACKAGE_NAME - 1); - strncpy(data->package, name, copy_len); - data->package[copy_len] = '\0'; - - list_add_tail(&data->list, my_ctx->uid_list); - - if (my_ctx->stats) - my_ctx->stats->total_found++; - - pr_info("UserDE UID: Found package: %s, uid: %u\n", data->package, data->uid); - - return FILLDIR_ACTOR_CONTINUE; -} - -static int scan_user_data_for_uids(struct list_head *uid_list) -{ - struct file *dir_file; - struct uid_scan_stats stats = {0}; - int ret = 0; - - if (!uid_list) { - return -EINVAL; - } - - dir_file = ksu_filp_open_compat(USER_DATA_PATH, O_RDONLY, 0); - if (IS_ERR(dir_file)) { - pr_err("UserDE UID: Failed to open %s, err: (%ld)\n", USER_DATA_PATH, PTR_ERR(dir_file)); - return PTR_ERR(dir_file); - } - - struct user_data_context ctx = { - .ctx.actor = user_data_actor, - .uid_list = uid_list, - .stats = &stats - }; - - ret = iterate_dir(dir_file, &ctx.ctx); - filp_close(dir_file, NULL); - - if (stats.errors_encountered > 0) { - pr_warn("Encountered %zu errors while scanning user data directory\n", - stats.errors_encountered); - } - - pr_info("UserDE UID: Scanned %s directory with %zu errors\n", - USER_DATA_PATH, stats.errors_encountered); - - return ret; -} - -FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, - int namelen, loff_t off, u64 ino, - unsigned int d_type) -{ - struct my_dir_context *my_ctx = - container_of(ctx, struct my_dir_context, ctx); - char dirpath[DATA_PATH_LEN]; - - if (!my_ctx) { - pr_err("Invalid context\n"); - return FILLDIR_ACTOR_STOP; - } - if (my_ctx->stop && *my_ctx->stop) { - pr_info("Stop searching\n"); - return FILLDIR_ACTOR_STOP; - } - - if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen)) - return FILLDIR_ACTOR_CONTINUE; // Skip "." and ".." - - if (d_type == DT_DIR && namelen >= 8 && !strncmp(name, "vmdl", 4) && - !strncmp(name + namelen - 4, ".tmp", 4)) { - pr_info("Skipping directory: %.*s\n", namelen, name); - return FILLDIR_ACTOR_CONTINUE; // Skip staging package - } - - - if (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir, - namelen, name) >= DATA_PATH_LEN) { - pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen, - name); - return FILLDIR_ACTOR_CONTINUE; - } - - if (d_type == DT_DIR && my_ctx->depth > 0 && - (my_ctx->stop && !*my_ctx->stop)) { - struct data_path *data = kmalloc(sizeof(struct data_path), GFP_ATOMIC); - - if (!data) { - pr_err("Failed to allocate memory for %s\n", dirpath); - return FILLDIR_ACTOR_CONTINUE; - } - - strscpy(data->dirpath, dirpath, DATA_PATH_LEN); - data->depth = my_ctx->depth - 1; - list_add_tail(&data->list, my_ctx->data_path_list); - } else { - if ((namelen == 8) && (strncmp(name, "base.apk", namelen) == 0)) { - struct apk_path_hash *pos, *n; - unsigned int hash = full_name_hash(NULL, dirpath, strlen(dirpath)); - list_for_each_entry(pos, &apk_path_hash_list, list) { - if (hash == pos->hash) { - pos->exists = true; - return FILLDIR_ACTOR_CONTINUE; - } - } - - int signature_index = -1; - bool is_multi_manager = is_dynamic_manager_apk( - dirpath, &signature_index); - - pr_info("Found new base.apk at path: %s, is_multi_manager: %d, signature_index: %d\n", - dirpath, is_multi_manager, signature_index); - - // Check for dynamic sign or multi-manager signatures - if (is_multi_manager && (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2)) { - crown_manager(dirpath, my_ctx->private_data, signature_index); - - struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC); - if (apk_data) { - apk_data->hash = hash; - apk_data->exists = true; - list_add_tail(&apk_data->list, &apk_path_hash_list); - } - - } else if (is_manager_apk(dirpath)) { - crown_manager(dirpath, my_ctx->private_data, 0); - *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); - } - } else { - struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC); - if (apk_data) { - apk_data->hash = hash; - apk_data->exists = true; - list_add_tail(&apk_data->list, &apk_path_hash_list); - } - } - } - } - - return FILLDIR_ACTOR_CONTINUE; -} - -void search_manager(const char *path, int depth, struct list_head *uid_data) -{ - int i, stop = 0; - struct list_head data_path_list; - INIT_LIST_HEAD(&data_path_list); - unsigned long data_app_magic = 0; - - // Initialize APK cache list - struct apk_path_hash *pos, *n; - list_for_each_entry(pos, &apk_path_hash_list, list) { - pos->exists = false; - } - - // First depth - struct data_path data; - strscpy(data.dirpath, path, DATA_PATH_LEN); - data.depth = depth; - list_add_tail(&data.list, &data_path_list); - - for (i = depth; i >= 0; i--) { - struct data_path *pos, *n; - - list_for_each_entry_safe(pos, n, &data_path_list, list) { - struct my_dir_context ctx = { .ctx.actor = my_actor, - .data_path_list = &data_path_list, - .parent_dir = pos->dirpath, - .private_data = uid_data, - .depth = pos->depth, - .stop = &stop }; - struct file *file; - - if (!stop) { - file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0); - if (IS_ERR(file)) { - pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file)); - goto skip_iterate; - } - - // grab magic on first folder, which is /data/app - if (!data_app_magic) { - if (file->f_inode->i_sb->s_magic) { - data_app_magic = file->f_inode->i_sb->s_magic; - pr_info("%s: dir: %s got magic! 0x%lx\n", __func__, pos->dirpath, data_app_magic); - } else { - filp_close(file, NULL); - goto skip_iterate; - } - } - - if (file->f_inode->i_sb->s_magic != data_app_magic) { - pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n", __func__, pos->dirpath, - file->f_inode->i_sb->s_magic, data_app_magic); - filp_close(file, NULL); - goto skip_iterate; - } - - iterate_dir(file, &ctx.ctx); - filp_close(file, NULL); - } -skip_iterate: - list_del(&pos->list); - if (pos != &data) - kfree(pos); - } - } - - // Remove stale cached APK entries - list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { - if (!pos->exists) { - list_del(&pos->list); - kfree(pos); - } - } -} - -static bool is_uid_exist(uid_t uid, char *package, void *data) -{ - struct list_head *list = (struct list_head *)data; - struct uid_data *np; - - bool exist = false; - list_for_each_entry (np, list, list) { - if (np->uid == uid % 100000 && - strncmp(np->package, package, KSU_MAX_PACKAGE_NAME) == 0) { - exist = true; - break; - } - } - return exist; -} - -extern bool ksu_uid_scanner_enabled; - -void track_throne() -{ - struct list_head uid_list; - struct uid_data *np, *n; - - // init uid list head - INIT_LIST_HEAD(&uid_list); - - if (ksu_uid_scanner_enabled) { - pr_info("Scanning %s directory..\n", KSU_UID_LIST_PATH); - if (uid_from_um_list(&uid_list) == 0) { - pr_info("Loaded UIDs from %s success\n", KSU_UID_LIST_PATH); - } else { - pr_warn("%s read failed, falling back to %s\n", KSU_UID_LIST_PATH, USER_DATA_PATH); - if (scan_user_data_for_uids(&uid_list) < 0) - goto out; - } - } else { - pr_info("User mode scan disabled, scanning %s\n", USER_DATA_PATH); - if (scan_user_data_for_uids(&uid_list) < 0) - goto out; - } - - // check if manager UID exists - bool manager_exist = false; - int current_manager_uid = ksu_get_manager_uid() % 100000; - - list_for_each_entry(np, &uid_list, list) { - if (np->uid == current_manager_uid) { - manager_exist = true; - break; - } - } - - if (!manager_exist && locked_manager_uid != KSU_INVALID_UID) { - pr_info("Manager APK removed, unlocking previous UID: %d\n", locked_manager_uid); - ksu_invalidate_manager_uid(); - locked_manager_uid = KSU_INVALID_UID; - } - - // Check if the Dynamic Manager exists (only check locked UIDs) - bool dynamic_manager_exist = false; - if (ksu_is_dynamic_manager_enabled() && locked_dynamic_manager_uid != KSU_INVALID_UID) { - list_for_each_entry(np, &uid_list, list) { - if (np->uid == locked_dynamic_manager_uid) { - dynamic_manager_exist = true; - break; - } - } - - if (!dynamic_manager_exist) { - pr_info("Dynamic manager APK removed, unlocking previous UID: %d\n", locked_dynamic_manager_uid); - ksu_remove_manager(locked_dynamic_manager_uid); - locked_dynamic_manager_uid = KSU_INVALID_UID; - } - } - - bool need_search = !manager_exist; - if (ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist) { - need_search = true; - } - - if (need_search) { - pr_info("Searching for manager(s)...\n"); - search_manager("/data/app", 2, &uid_list); - pr_info("Manager search finished\n"); - } - - // then prune the allowlist - ksu_prune_allowlist(is_uid_exist, &uid_list); -out: - // free uid_list - list_for_each_entry_safe(np, n, &uid_list, list) { - list_del(&np->list); - kfree(np); - } -} - -void ksu_throne_tracker_init() -{ - // nothing to do -} - -void ksu_throne_tracker_exit() -{ - // nothing to do -} diff --git a/kernel/throne_tracker.h b/kernel/throne_tracker.h deleted file mode 100644 index 5d7f4770..00000000 --- a/kernel/throne_tracker.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __KSU_H_UID_OBSERVER -#define __KSU_H_UID_OBSERVER - -void ksu_throne_tracker_init(); - -void ksu_throne_tracker_exit(); - -void track_throne(); - -#endif