From 118fcf507aac52f078481abea00db6339875660c Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 18 Nov 2025 21:39:31 +0800 Subject: [PATCH] kernel: fmt --- kernel/.clang-format | 14 +- kernel/Kconfig | 70 +- kernel/LICENSE | 2 +- kernel/allowlist.c | 146 ++-- kernel/allowlist.h | 2 +- kernel/apk_sign.c | 586 ++++++------- kernel/app_profile.c | 212 ++--- kernel/dynamic_manager.c | 728 ++++++++-------- kernel/dynamic_manager.h | 20 +- kernel/feature.c | 6 +- kernel/file_wrapper.c | 2 +- kernel/kernel_compat.c | 14 +- kernel/kernel_compat.h | 12 +- kernel/kernel_umount.c | 176 ++-- kernel/kernel_umount.h | 6 +- kernel/kpm/compact.c | 60 +- kernel/kpm/kpm.c | 300 +++---- kernel/kpm/kpm.h | 8 +- kernel/kpm/super_access.c | 290 +++---- kernel/kpm/super_access.h | 4 +- kernel/ksu.c | 66 +- kernel/ksu.h | 28 +- kernel/ksud.c | 778 ++++++++--------- kernel/ksud.h | 14 +- kernel/lsm_hooks.c | 54 +- kernel/manager.h | 18 +- kernel/manager_sign.h | 8 +- kernel/manual_su.c | 526 ++++++------ kernel/manual_su.h | 18 +- kernel/pkg_observer.c | 170 ++-- kernel/selinux/rules.c | 72 +- kernel/selinux/selinux.c | 82 +- kernel/selinux/selinux.h | 2 +- kernel/selinux/sepolicy.c | 124 +-- kernel/selinux/sepolicy.h | 22 +- kernel/setuid_hook.c | 144 ++-- kernel/setup.sh | 106 +-- kernel/sucompat.c | 376 ++++----- kernel/sucompat.h | 4 +- kernel/sulog.c | 448 +++++----- kernel/sulog.h | 62 +- kernel/supercalls.c | 1490 ++++++++++++++++----------------- kernel/supercalls.h | 90 +- kernel/syscall_hook_manager.c | 60 +- kernel/syscall_hook_manager.h | 8 +- kernel/throne_comm.c | 234 +++--- kernel/throne_tracker.c | 820 +++++++++--------- 47 files changed, 4241 insertions(+), 4241 deletions(-) diff --git a/kernel/.clang-format b/kernel/.clang-format index 6453cf96..427939c9 100644 --- a/kernel/.clang-format +++ b/kernel/.clang-format @@ -56,8 +56,8 @@ ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' #CompactNamespaces: false # Unknown to clang-format-4.0 ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false @@ -501,7 +501,7 @@ IncludeCategories: IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false #IndentPPDirectives: None # Unknown to clang-format-5.0 -IndentWidth: 4 +IndentWidth: 8 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true @@ -511,7 +511,7 @@ MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 -ObjCBlockIndentWidth: 4 +ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true @@ -543,6 +543,6 @@ SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp03 -TabWidth: 4 -UseTab: Never -... +TabWidth: 8 +UseTab: Always +... \ No newline at end of file diff --git a/kernel/Kconfig b/kernel/Kconfig index 88211ae8..4892ca7f 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -1,51 +1,51 @@ menu "KernelSU" config KSU - tristate "KernelSU function support" - default y - help - Enable kernel-level root privileges on Android System. - To compile as a module, choose M here: the - module will be called kernelsu. + tristate "KernelSU function support" + default y + help + Enable kernel-level root privileges on Android System. + To compile as a module, choose M here: the + module will be called kernelsu. config KSU_DEBUG - bool "KernelSU debug mode" - depends on KSU - default n - help - Enable KernelSU debug mode. + bool "KernelSU debug mode" + depends on KSU + default n + help + Enable KernelSU debug mode. config KSU_MULTI_MANAGER_SUPPORT - bool "Multi KernelSU manager support" - depends on KSU - default n - help - Enable multi KernelSU manager support + bool "Multi KernelSU manager support" + depends on KSU + default n + help + Enable multi KernelSU manager support config KSU_ALLOWLIST_WORKAROUND - bool "KernelSU Session Keyring Init workaround" - depends on KSU - default n - help - Enable session keyring init workaround for problematic devices. - Useful for situations where the SU allowlist is not kept after a reboot + bool "KernelSU Session Keyring Init workaround" + depends on KSU + default n + help + Enable session keyring init workaround for problematic devices. + Useful for situations where the SU allowlist is not kept after a reboot config KPM - bool "Enable SukiSU KPM" - depends on KSU && 64BIT - select KALLSYMS - select KALLSYMS_ALL - default n - help - Enabling this option will activate the KPM feature of SukiSU. - This option is suitable for scenarios where you need to force KPM to be enabled. - but it may affect system stability. + bool "Enable SukiSU KPM" + depends on KSU && 64BIT + select KALLSYMS + select KALLSYMS_ALL + default n + help + Enabling this option will activate the KPM feature of SukiSU. + This option is suitable for scenarios where you need to force KPM to be enabled. + but it may affect system stability. config KSU_MANUAL_HOOK - bool "Hook KernelSU manually" - depends on KSU != m - help - If enabled, Hook required KernelSU syscalls with manually-patched function. + bool "Hook KernelSU manually" + depends on KSU != m + help + If enabled, Hook required KernelSU syscalls with manually-patched function. menu "KernelSU - SUSFS" diff --git a/kernel/LICENSE b/kernel/LICENSE index d159169d..ecbc0593 100644 --- a/kernel/LICENSE +++ b/kernel/LICENSE @@ -336,4 +336,4 @@ This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +Public License instead of this License. \ No newline at end of file diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 061fb533..9a68e054 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -83,7 +83,7 @@ static void init_default_profiles(void) default_root_profile.groups_count = 1; default_root_profile.groups[0] = 0; memcpy(&default_root_profile.capabilities.effective, &full_cap, - sizeof(default_root_profile.capabilities.effective)); + sizeof(default_root_profile.capabilities.effective)); default_root_profile.namespaces = 0; strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); @@ -127,7 +127,7 @@ static void ksu_grant_root_to_shell(void) }; strcpy(profile.key, "com.android.shell"); strcpy(profile.rp_config.profile.selinux_domain, - KSU_DEFAULT_SELINUX_DOMAIN); + KSU_DEFAULT_SELINUX_DOMAIN); ksu_set_app_profile(&profile, false); } #endif @@ -199,7 +199,7 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist) p = list_entry(pos, struct perm_data, list); // both uid and package must match, otherwise it will break multiple package with different user id if (profile->current_uid == p->profile.current_uid && - !strcmp(profile->key, p->profile.key)) { + !strcmp(profile->key, p->profile.key)) { // found it, just override it all! memcpy(&p->profile, profile, sizeof(*profile)); result = true; @@ -238,9 +238,9 @@ out: } else { if (profile->allow_su) { /* - * 1024 apps with uid higher than BITMAP_UID_MAX - * registered to request superuser? - */ + * 1024 apps with uid higher than BITMAP_UID_MAX + * registered to request superuser? + */ if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) { pr_err("too many apps registered\n"); WARN_ON(1); @@ -258,13 +258,13 @@ out: if (unlikely(!strcmp(profile->key, "$"))) { // set default non root profile memcpy(&default_non_root_profile, &profile->nrp_config.profile, - sizeof(default_non_root_profile)); + sizeof(default_non_root_profile)); } if (unlikely(!strcmp(profile->key, "#"))) { // set default root profile memcpy(&default_root_profile, &profile->rp_config.profile, - sizeof(default_root_profile)); + sizeof(default_root_profile)); } if (persist) { @@ -286,7 +286,7 @@ bool __ksu_is_allow_uid(uid_t uid) } if (likely(ksu_is_manager_uid_valid()) && - unlikely(ksu_get_manager_uid() == uid)) { + unlikely(ksu_get_manager_uid() == uid)) { // manager is always allowed! return true; } @@ -317,7 +317,7 @@ bool ksu_uid_should_umount(uid_t uid) { struct app_profile profile = { .current_uid = uid }; if (likely(ksu_is_manager_uid_valid()) && - unlikely(ksu_get_manager_uid() == uid)) { + unlikely(ksu_get_manager_uid() == uid)) { // we should not umount on manager! return false; } @@ -387,19 +387,19 @@ static void do_persistent_allow_list(struct callback_head *_cb) KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (IS_ERR(fp)) { pr_err("save_allow_list create file failed: %ld\n", - PTR_ERR(fp)); + PTR_ERR(fp)); goto unlock; } // store magic and version if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != - sizeof(magic)) { + sizeof(magic)) { pr_err("save_allow_list write magic failed.\n"); goto close_file; } if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != - sizeof(version)) { + sizeof(version)) { pr_err("save_allow_list write version failed.\n"); goto close_file; } @@ -466,14 +466,14 @@ void ksu_load_allow_list(void) // verify magic if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != - sizeof(magic) || - magic != FILE_MAGIC) { + sizeof(magic) || + magic != FILE_MAGIC) { pr_err("allowlist file invalid: %d!\n", magic); goto exit; } if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != - sizeof(version)) { + sizeof(version)) { pr_err("allowlist read version: %d failed\n", version); goto exit; } @@ -484,7 +484,7 @@ void ksu_load_allow_list(void) struct app_profile profile; ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile), - &off); + &off); if (ret <= 0) { pr_info("load_allow_list read err: %zd\n", ret); @@ -572,77 +572,77 @@ void ksu_allowlist_exit(void) #ifdef CONFIG_KSU_MANUAL_SU bool ksu_temp_grant_root_once(uid_t uid) { - struct app_profile profile = { - .version = KSU_APP_PROFILE_VER, - .allow_su = true, - .current_uid = uid, - }; + struct app_profile profile = { + .version = KSU_APP_PROFILE_VER, + .allow_su = true, + .current_uid = uid, + }; - const char *default_key = "com.temp.once"; + const char *default_key = "com.temp.once"; - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool found = false; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + bool found = false; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - if (p->profile.current_uid == uid) { - strcpy(profile.key, p->profile.key); - found = true; - break; - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + if (p->profile.current_uid == uid) { + strcpy(profile.key, p->profile.key); + found = true; + break; + } + } - if (!found) { - strcpy(profile.key, default_key); - } + if (!found) { + strcpy(profile.key, default_key); + } - profile.rp_config.profile.uid = default_root_profile.uid; - profile.rp_config.profile.gid = default_root_profile.gid; - profile.rp_config.profile.groups_count = default_root_profile.groups_count; - memcpy(profile.rp_config.profile.groups, default_root_profile.groups, sizeof(default_root_profile.groups)); - memcpy(&profile.rp_config.profile.capabilities, &default_root_profile.capabilities, sizeof(default_root_profile.capabilities)); - profile.rp_config.profile.namespaces = default_root_profile.namespaces; - strcpy(profile.rp_config.profile.selinux_domain, default_root_profile.selinux_domain); + profile.rp_config.profile.uid = default_root_profile.uid; + profile.rp_config.profile.gid = default_root_profile.gid; + profile.rp_config.profile.groups_count = default_root_profile.groups_count; + memcpy(profile.rp_config.profile.groups, default_root_profile.groups, sizeof(default_root_profile.groups)); + memcpy(&profile.rp_config.profile.capabilities, &default_root_profile.capabilities, sizeof(default_root_profile.capabilities)); + profile.rp_config.profile.namespaces = default_root_profile.namespaces; + strcpy(profile.rp_config.profile.selinux_domain, default_root_profile.selinux_domain); - bool ok = ksu_set_app_profile(&profile, false); - if (ok) - pr_info("pending_root: UID=%d granted and persisted\n", uid); - return ok; + bool ok = ksu_set_app_profile(&profile, false); + if (ok) + pr_info("pending_root: UID=%d granted and persisted\n", uid); + return ok; } void ksu_temp_revoke_root_once(uid_t uid) { - struct app_profile profile = { - .version = KSU_APP_PROFILE_VER, - .allow_su = false, - .current_uid = uid, - }; + struct app_profile profile = { + .version = KSU_APP_PROFILE_VER, + .allow_su = false, + .current_uid = uid, + }; - const char *default_key = "com.temp.once"; + const char *default_key = "com.temp.once"; - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool found = false; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + bool found = false; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - if (p->profile.current_uid == uid) { - strcpy(profile.key, p->profile.key); - found = true; - break; - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + if (p->profile.current_uid == uid) { + strcpy(profile.key, p->profile.key); + found = true; + break; + } + } - if (!found) { - strcpy(profile.key, default_key); - } + if (!found) { + strcpy(profile.key, default_key); + } - profile.nrp_config.profile.umount_modules = default_non_root_profile.umount_modules; - strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); + profile.nrp_config.profile.umount_modules = default_non_root_profile.umount_modules; + strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); - ksu_set_app_profile(&profile, false); - persistent_allow_list(); - pr_info("pending_root: UID=%d removed and persist updated\n", uid); + ksu_set_app_profile(&profile, false); + persistent_allow_list(); + pr_info("pending_root: UID=%d removed and persist updated\n", uid); } #endif diff --git a/kernel/allowlist.h b/kernel/allowlist.h index 68e04bab..536afa51 100644 --- a/kernel/allowlist.h +++ b/kernel/allowlist.h @@ -23,7 +23,7 @@ bool __ksu_is_allow_uid(uid_t uid); // Check if the uid is in allow list, or current is ksu domain root bool __ksu_is_allow_uid_for_current(uid_t uid); -#define ksu_is_allow_uid_for_current(uid) \ +#define ksu_is_allow_uid_for_current(uid) \ unlikely(__ksu_is_allow_uid_for_current(uid)) bool ksu_get_allow_list(int *array, int *length, bool allow); diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c index 04d8ae97..1b4ef157 100644 --- a/kernel/apk_sign.c +++ b/kernel/apk_sign.c @@ -21,68 +21,68 @@ #include "kernel_compat.h" struct sdesc { - struct shash_desc shash; - char ctx[]; + struct shash_desc shash; + char ctx[]; }; static apk_sign_key_t apk_sign_keys[] = { - {EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // SukiSU + {EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // SukiSU #ifdef CONFIG_KSU_MULTI_MANAGER_SUPPORT - {EXPECTED_SIZE_WEISHU, EXPECTED_HASH_WEISHU}, // Official - {EXPECTED_SIZE_5EC1CFF, EXPECTED_HASH_5EC1CFF}, // 5ec1cff/KernelSU - {EXPECTED_SIZE_RSUNTK, EXPECTED_HASH_RSUNTK}, // rsuntk/KernelSU - {EXPECTED_SIZE_NEKO, EXPECTED_HASH_NEKO}, // Neko/KernelSU + {EXPECTED_SIZE_WEISHU, EXPECTED_HASH_WEISHU}, // Official + {EXPECTED_SIZE_5EC1CFF, EXPECTED_HASH_5EC1CFF}, // 5ec1cff/KernelSU + {EXPECTED_SIZE_RSUNTK, EXPECTED_HASH_RSUNTK}, // rsuntk/KernelSU + {EXPECTED_SIZE_NEKO, EXPECTED_HASH_NEKO}, // Neko/KernelSU #ifdef EXPECTED_SIZE - {EXPECTED_SIZE, EXPECTED_HASH}, // Custom + {EXPECTED_SIZE, EXPECTED_HASH}, // Custom #endif #endif }; static struct sdesc *init_sdesc(struct crypto_shash *alg) { - struct sdesc *sdesc; - int size; + struct sdesc *sdesc; + int size; - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kzalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - return sdesc; + size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); + sdesc = kzalloc(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) + unsigned int datalen, unsigned char *digest) { - struct sdesc *sdesc; - int ret; + struct sdesc *sdesc; + int ret; - sdesc = init_sdesc(alg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc sdesc\n"); - return PTR_ERR(sdesc); - } + 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; + 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) + unsigned char *digest) { - struct crypto_shash *alg; - char *hash_alg_name = "sha256"; - int ret; + 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; + 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; } @@ -90,307 +90,307 @@ 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; - } + 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 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; + 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; + 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 + 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; + *offset += 0x4 * 3; - ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length + ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length - *pos += *size4; - *offset += 0x4 + *size4; + *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; + 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; - } - } + 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]; + for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) { + sign_key = apk_sign_keys[i]; - if (*size4 != sign_key.size) - continue; - *offset += *size4; + 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 (ksu_sha256(cert, *size4, digest) < 0 ) { - pr_info("sha256 error\n"); - return false; - } + 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'; + 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; + 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; + 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"; + struct zip_entry_header header; + const char MANIFEST[] = "META-INF/MANIFEST.MF"; - loff_t pos = 0; + 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'; + 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; - } + // 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; - } + // Skip to the next entry + pos += header.extra_field_length + header.compressed_size; + } - return false; + 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; + unsigned char buffer[0x11] = { 0 }; + u32 size4; + u64 size8, size_of_block; - loff_t pos; + 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; - } + 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; - } + // 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; + // 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; - } - } + // 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; + 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; - } + 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; - } + 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 { + 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); + pr_info("Unknown id: 0x%08x\n", id); #endif - } - pos += (size8 - offset); - } + } + pos += (size8 - offset); + } - if (v2_signing_blocks != 1) { + if (v2_signing_blocks != 1) { #ifdef CONFIG_KSU_DEBUG - pr_err("Unexpected v2 signature count: %d\n", - v2_signing_blocks); + pr_err("Unexpected v2 signature count: %d\n", + v2_signing_blocks); #endif - v2_signing_valid = false; - } + 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; - } - } + 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); + filp_close(fp, 0); - if (v3_signing_exist || v3_1_signing_exist) { + if (v3_signing_exist || v3_1_signing_exist) { #ifdef CONFIG_KSU_DEBUG - pr_err("Unexpected v3 signature scheme found!\n"); + pr_err("Unexpected v3 signature scheme found!\n"); #endif - return false; - } + 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; + 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 @@ -401,28 +401,28 @@ int ksu_debug_manager_uid = -1; 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; + 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, + .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); + &ksu_debug_manager_uid, S_IRUSR | S_IWUSR); #endif bool is_manager_apk(char *path) { - return check_v2_signature(path, false, NULL); + 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); + return check_v2_signature(path, true, signature_index); } diff --git a/kernel/app_profile.c b/kernel/app_profile.c index 860af4f8..a3dfdf3c 100644 --- a/kernel/app_profile.c +++ b/kernel/app_profile.c @@ -29,9 +29,9 @@ #include "sulog.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION (6, 7, 0) - static struct group_info root_groups = { .usage = REFCOUNT_INIT(2), }; + static struct group_info root_groups = { .usage = REFCOUNT_INIT(2), }; #else - static struct group_info root_groups = { .usage = ATOMIC_INIT(2) }; + static struct group_info root_groups = { .usage = ATOMIC_INIT(2) }; #endif static void setup_groups(struct root_profile *profile, struct cred *cred) @@ -86,7 +86,7 @@ void disable_seccomp(struct task_struct *tsk) assert_spin_locked(&tsk->sighand->siglock); // disable seccomp -#if defined(CONFIG_GENERIC_ENTRY) && \ +#if defined(CONFIG_GENERIC_ENTRY) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) clear_syscall_work(SECCOMP); #else @@ -101,13 +101,13 @@ void disable_seccomp(struct task_struct *tsk) atomic_set(&tsk->seccomp.filter_count, 0); #endif // some old kernel backport seccomp_filter_release.. -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) && \ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) && \ defined(KSU_OPTIONAL_SECCOMP_FILTER_RELEASE) seccomp_filter_release(tsk); #else // never, ever call seccomp_filter_release on 6.10+ (no effect) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0)) seccomp_filter_release(tsk); #else #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) @@ -151,7 +151,7 @@ void escape_with_root_profile(void) cred->securebits = 0; BUILD_BUG_ON(sizeof(profile->capabilities.effective) != - sizeof(kernel_cap_t)); + sizeof(kernel_cap_t)); // setup capabilities // we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process @@ -159,11 +159,11 @@ void escape_with_root_profile(void) u64 cap_for_ksud = profile->capabilities.effective | CAP_DAC_READ_SEARCH; memcpy(&cred->cap_effective, &cap_for_ksud, - sizeof(cred->cap_effective)); + sizeof(cred->cap_effective)); memcpy(&cred->cap_permitted, &profile->capabilities.effective, - sizeof(cred->cap_permitted)); + sizeof(cred->cap_permitted)); memcpy(&cred->cap_bset, &profile->capabilities.effective, - sizeof(cred->cap_bset)); + sizeof(cred->cap_bset)); setup_groups(profile, cred); @@ -177,7 +177,7 @@ void escape_with_root_profile(void) setup_selinux(profile->selinux_domain); #if __SULOG_GATE - ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root"); + ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root"); #endif #ifndef CONFIG_KSU_SUSFS @@ -193,149 +193,149 @@ void escape_with_root_profile(void) #include "ksud.h" #ifndef DEVPTS_SUPER_MAGIC -#define DEVPTS_SUPER_MAGIC 0x1cd1 +#define DEVPTS_SUPER_MAGIC 0x1cd1 #endif static int __manual_su_handle_devpts(struct inode *inode) { - if (!current->mm) { - return 0; - } + if (!current->mm) { + return 0; + } - uid_t uid = current_uid().val; - if (uid % 100000 < 10000) { - // not untrusted_app, ignore it - return 0; - } + uid_t uid = current_uid().val; + if (uid % 100000 < 10000) { + // not untrusted_app, ignore it + return 0; + } - if (likely(!ksu_is_allow_uid_for_current(uid))) - return 0; + if (likely(!ksu_is_allow_uid_for_current(uid))) + return 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || defined(KSU_OPTIONAL_SELINUX_INODE) - struct inode_security_struct *sec = selinux_inode(inode); + struct inode_security_struct *sec = selinux_inode(inode); #else - struct inode_security_struct *sec = - (struct inode_security_struct *)inode->i_security; + struct inode_security_struct *sec = + (struct inode_security_struct *)inode->i_security; #endif - if (ksu_file_sid && sec) - sec->sid = ksu_file_sid; + if (ksu_file_sid && sec) + sec->sid = ksu_file_sid; - return 0; + return 0; } static void disable_seccomp_for_task(struct task_struct *tsk) { - assert_spin_locked(&tsk->sighand->siglock); + assert_spin_locked(&tsk->sighand->siglock); #ifdef CONFIG_SECCOMP - if (tsk->seccomp.mode == SECCOMP_MODE_DISABLED && !tsk->seccomp.filter) - return; + if (tsk->seccomp.mode == SECCOMP_MODE_DISABLED && !tsk->seccomp.filter) + return; #endif - clear_tsk_thread_flag(tsk, TIF_SECCOMP); + clear_tsk_thread_flag(tsk, TIF_SECCOMP); #ifdef CONFIG_SECCOMP - tsk->seccomp.mode = SECCOMP_MODE_DISABLED; - if (tsk->seccomp.filter) { + tsk->seccomp.mode = SECCOMP_MODE_DISABLED; + if (tsk->seccomp.filter) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) - seccomp_filter_release(tsk); + seccomp_filter_release(tsk); #else - put_seccomp_filter(tsk); - tsk->seccomp.filter = NULL; + put_seccomp_filter(tsk); + tsk->seccomp.filter = NULL; #endif - } + } #endif } void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) { - struct cred *newcreds; - struct task_struct *target_task; + struct cred *newcreds; + struct task_struct *target_task; - pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid); + pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid); - // Find target task by PID - rcu_read_lock(); - target_task = pid_task(find_vpid(target_pid), PIDTYPE_PID); - if (!target_task) { - rcu_read_unlock(); - pr_err("cmd_su: target task not found for PID: %d\n", target_pid); + // Find target task by PID + rcu_read_lock(); + target_task = pid_task(find_vpid(target_pid), PIDTYPE_PID); + if (!target_task) { + rcu_read_unlock(); + pr_err("cmd_su: target task not found for PID: %d\n", target_pid); #if __SULOG_GATE - ksu_sulog_report_su_grant(target_uid, "cmd_su", "target_not_found"); + ksu_sulog_report_su_grant(target_uid, "cmd_su", "target_not_found"); #endif - return; - } - get_task_struct(target_task); - rcu_read_unlock(); + return; + } + get_task_struct(target_task); + rcu_read_unlock(); - if (task_uid(target_task).val == 0) { - pr_warn("cmd_su: target task is already root, PID: %d\n", target_pid); - put_task_struct(target_task); - return; - } + if (task_uid(target_task).val == 0) { + pr_warn("cmd_su: target task is already root, PID: %d\n", target_pid); + put_task_struct(target_task); + return; + } - newcreds = prepare_kernel_cred(target_task); - if (newcreds == NULL) { - pr_err("cmd_su: failed to allocate new cred for PID: %d\n", target_pid); + newcreds = prepare_kernel_cred(target_task); + if (newcreds == NULL) { + pr_err("cmd_su: failed to allocate new cred for PID: %d\n", target_pid); #if __SULOG_GATE - ksu_sulog_report_su_grant(target_uid, "cmd_su", "cred_alloc_failed"); + ksu_sulog_report_su_grant(target_uid, "cmd_su", "cred_alloc_failed"); #endif - put_task_struct(target_task); - return; - } + put_task_struct(target_task); + return; + } - struct root_profile *profile = ksu_get_root_profile(target_uid); + struct root_profile *profile = ksu_get_root_profile(target_uid); - newcreds->uid.val = profile->uid; - newcreds->suid.val = profile->uid; - newcreds->euid.val = profile->uid; - newcreds->fsuid.val = profile->uid; + newcreds->uid.val = profile->uid; + newcreds->suid.val = profile->uid; + newcreds->euid.val = profile->uid; + newcreds->fsuid.val = profile->uid; - newcreds->gid.val = profile->gid; - newcreds->fsgid.val = profile->gid; - newcreds->sgid.val = profile->gid; - newcreds->egid.val = profile->gid; - newcreds->securebits = 0; + newcreds->gid.val = profile->gid; + newcreds->fsgid.val = profile->gid; + newcreds->sgid.val = profile->gid; + newcreds->egid.val = profile->gid; + newcreds->securebits = 0; - u64 cap_for_cmd_su = profile->capabilities.effective | CAP_DAC_READ_SEARCH | CAP_SETUID | CAP_SETGID; - memcpy(&newcreds->cap_effective, &cap_for_cmd_su, sizeof(newcreds->cap_effective)); - memcpy(&newcreds->cap_permitted, &profile->capabilities.effective, sizeof(newcreds->cap_permitted)); - memcpy(&newcreds->cap_bset, &profile->capabilities.effective, sizeof(newcreds->cap_bset)); + u64 cap_for_cmd_su = profile->capabilities.effective | CAP_DAC_READ_SEARCH | CAP_SETUID | CAP_SETGID; + memcpy(&newcreds->cap_effective, &cap_for_cmd_su, sizeof(newcreds->cap_effective)); + memcpy(&newcreds->cap_permitted, &profile->capabilities.effective, sizeof(newcreds->cap_permitted)); + memcpy(&newcreds->cap_bset, &profile->capabilities.effective, sizeof(newcreds->cap_bset)); - setup_groups(profile, newcreds); - task_lock(target_task); + setup_groups(profile, newcreds); + task_lock(target_task); - const struct cred *old_creds = get_task_cred(target_task); + const struct cred *old_creds = get_task_cred(target_task); - rcu_assign_pointer(target_task->real_cred, newcreds); - rcu_assign_pointer(target_task->cred, get_cred(newcreds)); - task_unlock(target_task); + rcu_assign_pointer(target_task->real_cred, newcreds); + rcu_assign_pointer(target_task->cred, get_cred(newcreds)); + task_unlock(target_task); - if (target_task->sighand) { - spin_lock_irqsave(&target_task->sighand->siglock, flags); - disable_seccomp_for_task(target_task); - spin_unlock_irqrestore(&target_task->sighand->siglock, flags); - } + if (target_task->sighand) { + spin_lock_irqsave(&target_task->sighand->siglock, flags); + disable_seccomp_for_task(target_task); + spin_unlock_irqrestore(&target_task->sighand->siglock, flags); + } - setup_selinux(profile->selinux_domain); - put_cred(old_creds); - wake_up_process(target_task); + setup_selinux(profile->selinux_domain); + put_cred(old_creds); + wake_up_process(target_task); - if (target_task->signal->tty) { - struct inode *inode = target_task->signal->tty->driver_data; - if (inode && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) { - __manual_su_handle_devpts(inode); - } - } + if (target_task->signal->tty) { + struct inode *inode = target_task->signal->tty->driver_data; + if (inode && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) { + __manual_su_handle_devpts(inode); + } + } - put_task_struct(target_task); + put_task_struct(target_task); #if __SULOG_GATE - ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation"); + ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation"); #endif #ifndef CONFIG_KSU_SUSFS - struct task_struct *p = current; - struct task_struct *t; - for_each_thread (p, t) { - ksu_set_task_tracepoint_flag(t); - } + struct task_struct *p = current; + struct task_struct *t; + for_each_thread (p, t) { + ksu_set_task_tracepoint_flag(t); + } #endif - pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid); + pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid); } #endif diff --git a/kernel/dynamic_manager.c b/kernel/dynamic_manager.c index df49f65d..d6322324 100644 --- a/kernel/dynamic_manager.c +++ b/kernel/dynamic_manager.c @@ -24,9 +24,9 @@ // Dynamic sign configuration static struct dynamic_manager_config dynamic_manager = { - .size = 0x300, - .hash = "0000000000000000000000000000000000000000000000000000000000000000", - .is_set = 0 + .size = 0x300, + .hash = "0000000000000000000000000000000000000000000000000000000000000000", + .is_set = 0 }; // Multi-manager state @@ -41,465 +41,465 @@ 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; + 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"); + 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); + 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; + 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; + 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); + 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; - } + 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; + // 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; + 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); + 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; - } + 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; - } + 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, &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, &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; - } + 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"); + pr_info("Dynamic sign config saved successfully\n"); exit: - filp_close(fp, 0); + 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; + 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; - } + 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, &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; - } + 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); + 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; - } + 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 (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 (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; - } + 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; - } - } + // 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); + 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); + pr_info("Dynamic sign config loaded: size=0x%x, hash=%.16s...\n", + loaded_config.size, loaded_config.hash); exit: - filp_close(fp, 0); + filp_close(fp, 0); } static bool persistent_dynamic_manager(void) { - return ksu_queue_work(&save_dynamic_manager_work); + 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]; + loff_t off = 0; + struct file *fp; + char zero_buffer[512]; - memset(zero_buffer, 0, sizeof(zero_buffer)); + 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; - } + 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"); - } + // 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); + filp_close(fp, 0); } static bool clear_dynamic_manager_file(void) { - return ksu_queue_work(&clear_dynamic_manager_work); + 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; + 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)); + strscpy(dynamic_manager.hash, config->hash, sizeof(dynamic_manager.hash)); #else - strlcpy(dynamic_manager.hash, config->hash, sizeof(dynamic_manager.hash)); + 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; + 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)); + strscpy(config->hash, dynamic_manager.hash, sizeof(config->hash)); #else - strlcpy(config->hash, dynamic_manager.hash, sizeof(config->hash)); + 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; - } + 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; + return ret; } bool ksu_load_dynamic_manager(void) { - return ksu_queue_work(&load_dynamic_manager_work); + 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; - } + 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"); + 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"); + 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; + 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 index 1b5a5cbd..437f6ade 100644 --- a/kernel/dynamic_manager.h +++ b/kernel/dynamic_manager.h @@ -10,25 +10,25 @@ #define DYNAMIC_SIGN_INDEX 100 struct dynamic_sign_key { - unsigned int size; - const char *hash; + unsigned int size; + const char *hash; }; #define DYNAMIC_SIGN_DEFAULT_CONFIG { \ - .size = 0x300, \ - .hash = "0000000000000000000000000000000000000000000000000000000000000000" \ + .size = 0x300, \ + .hash = "0000000000000000000000000000000000000000000000000000000000000000" \ } struct dynamic_manager_config { - unsigned int size; - char hash[65]; - int is_set; + unsigned int size; + char hash[65]; + int is_set; }; struct manager_info { - uid_t uid; - int signature_index; - bool is_active; + uid_t uid; + int signature_index; + bool is_active; }; // Dynamic sign operations diff --git a/kernel/feature.c b/kernel/feature.c index 3bd6f69d..38901b84 100644 --- a/kernel/feature.c +++ b/kernel/feature.c @@ -21,7 +21,7 @@ int ksu_register_feature_handler(const struct ksu_feature_handler *handler) if (!handler->get_handler && !handler->set_handler) { pr_err("feature: no handler provided for feature %u\n", - handler->feature_id); + handler->feature_id); return -EINVAL; } @@ -104,7 +104,7 @@ int ksu_get_feature(u32 feature_id, u64 *value, bool *supported) ret = handler->get_handler(value); if (ret) { pr_err("feature: get_handler for %u failed: %d\n", feature_id, - ret); + ret); } out: @@ -141,7 +141,7 @@ int ksu_set_feature(u32 feature_id, u64 value) ret = handler->set_handler(value); if (ret) { pr_err("feature: set_handler for %u failed: %d\n", feature_id, - ret); + ret); } out: diff --git a/kernel/file_wrapper.c b/kernel/file_wrapper.c index 91695bd9..be95ac4f 100644 --- a/kernel/file_wrapper.c +++ b/kernel/file_wrapper.c @@ -320,7 +320,7 @@ static int ksu_wrapper_fadvise(struct file *fp, loff_t off1, loff_t off2, int fl static int ksu_wrapper_release(struct inode *inode, struct file *filp) { ksu_delete_file_wrapper(filp->private_data); - return 0; + return 0; } struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp) { diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c index 970bae71..6ad7b57f 100644 --- a/kernel/kernel_compat.c +++ b/kernel/kernel_compat.c @@ -9,7 +9,7 @@ #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) #include #include @@ -40,10 +40,10 @@ static int install_session_keyring(struct key *keyring) struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) if (init_session_keyring != NULL && !current_cred()->session_keyring && - (current->flags & PF_WQ_WORKER)) { + (current->flags & PF_WQ_WORKER)) { pr_info("installing init session keyring for older kernel\n"); install_session_keyring(init_session_keyring); } @@ -52,9 +52,9 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) } ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, - loff_t *pos) + loff_t *pos) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ defined(KSU_OPTIONAL_KERNEL_READ) return kernel_read(p, buf, count, pos); #else @@ -70,7 +70,7 @@ ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ defined(KSU_OPTIONAL_KERNEL_WRITE) return kernel_write(p, buf, count, pos); #else @@ -83,7 +83,7 @@ ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, #endif } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) || \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) || \ defined(KSU_OPTIONAL_STRNCPY) long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, long count) diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index ed0f19e0..6e376e9e 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -13,9 +13,9 @@ * Huawei Hisi Kernel EBITMAP Enable or Disable Flag , * From ss/ebitmap.h */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) && \ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) && \ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) #ifdef HISI_SELINUX_EBITMAP_RO #define CONFIG_IS_HW_HISI @@ -36,11 +36,11 @@ extern long ksu_strncpy_from_user_nofault(char *dst, extern struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode); extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, - loff_t *pos); + loff_t *pos); extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, - size_t count, loff_t *pos); + size_t count, loff_t *pos); -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) extern struct key *init_session_keyring; #endif diff --git a/kernel/kernel_umount.c b/kernel/kernel_umount.c index ed66f531..acb6c2c2 100644 --- a/kernel/kernel_umount.c +++ b/kernel/kernel_umount.c @@ -35,23 +35,23 @@ bool ksu_kernel_umount_enabled = true; static int kernel_umount_feature_get(u64 *value) { - *value = ksu_kernel_umount_enabled ? 1 : 0; - return 0; + *value = ksu_kernel_umount_enabled ? 1 : 0; + return 0; } static int kernel_umount_feature_set(u64 value) { - bool enable = value != 0; - ksu_kernel_umount_enabled = enable; - pr_info("kernel_umount: set to %d\n", enable); - return 0; + bool enable = value != 0; + ksu_kernel_umount_enabled = enable; + pr_info("kernel_umount: set to %d\n", enable); + return 0; } static const struct ksu_feature_handler kernel_umount_handler = { - .feature_id = KSU_FEATURE_KERNEL_UMOUNT, - .name = "kernel_umount", - .get_handler = kernel_umount_feature_get, - .set_handler = kernel_umount_feature_set, + .feature_id = KSU_FEATURE_KERNEL_UMOUNT, + .name = "kernel_umount", + .get_handler = kernel_umount_feature_get, + .set_handler = kernel_umount_feature_set, }; #ifdef CONFIG_KSU_SUSFS @@ -102,130 +102,130 @@ static void try_umount(const char *mnt, int flags) void try_umount(const char *mnt, int flags) #endif // #ifndef CONFIG_KSU_SUSFS_TRY_UMOUNT { - struct path path; - int err = kern_path(mnt, 0, &path); - if (err) { - return; - } + struct path path; + int err = kern_path(mnt, 0, &path); + if (err) { + return; + } - if (path.dentry != path.mnt->mnt_root) { - // it is not root mountpoint, maybe umounted by others already. - path_put(&path); - return; - } + if (path.dentry != path.mnt->mnt_root) { + // it is not root mountpoint, maybe umounted by others already. + path_put(&path); + return; + } #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG) - if (susfs_is_log_enabled) { - pr_info("susfs: umounting '%s'\n", mnt); - } + if (susfs_is_log_enabled) { + pr_info("susfs: umounting '%s'\n", mnt); + } #endif // #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG) - ksu_umount_mnt(&path, flags); + ksu_umount_mnt(&path, flags); } #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT void susfs_try_umount_all(void) { - susfs_try_umount(); + susfs_try_umount(); } #endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT #if !defined(CONFIG_KSU_SUSFS) || !defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) struct umount_tw { - struct callback_head cb; - const struct cred *old_cred; + struct callback_head cb; + const struct cred *old_cred; }; static void umount_tw_func(struct callback_head *cb) { - struct umount_tw *tw = container_of(cb, struct umount_tw, cb); - const struct cred *saved = NULL; - if (tw->old_cred) { - saved = override_creds(tw->old_cred); - } + struct umount_tw *tw = container_of(cb, struct umount_tw, cb); + const struct cred *saved = NULL; + if (tw->old_cred) { + saved = override_creds(tw->old_cred); + } - struct mount_entry *entry; - down_read(&mount_list_lock); - list_for_each_entry(entry, &mount_list, list) { - pr_info("%s: unmounting: %s flags 0x%x\n", __func__, entry->umountable, entry->flags); - try_umount(entry->umountable, entry->flags); - } - up_read(&mount_list_lock); + struct mount_entry *entry; + down_read(&mount_list_lock); + list_for_each_entry(entry, &mount_list, list) { + pr_info("%s: unmounting: %s flags 0x%x\n", __func__, entry->umountable, entry->flags); + try_umount(entry->umountable, entry->flags); + } + up_read(&mount_list_lock); - if (saved) - revert_creds(saved); + if (saved) + revert_creds(saved); - if (tw->old_cred) - put_cred(tw->old_cred); + if (tw->old_cred) + put_cred(tw->old_cred); - kfree(tw); + kfree(tw); } int ksu_handle_umount(uid_t old_uid, uid_t new_uid) { - struct umount_tw *tw; + struct umount_tw *tw; #if defined(CONFIG_KSU_SUSFS) || !defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) - // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it! - if (!ksu_module_mounted) { - return 0; - } + // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it! + if (!ksu_module_mounted) { + return 0; + } - if (!ksu_kernel_umount_enabled) { - return 0; - } + if (!ksu_kernel_umount_enabled) { + return 0; + } - // FIXME: isolated process which directly forks from zygote is not handled - if (!is_appuid(new_uid)) { - return 0; - } + // FIXME: isolated process which directly forks from zygote is not handled + if (!is_appuid(new_uid)) { + return 0; + } - if (!ksu_uid_should_umount(new_uid)) { - return 0; - } + if (!ksu_uid_should_umount(new_uid)) { + return 0; + } - // check old process's selinux context, if it is not zygote, ignore it! - // because some su apps may setuid to untrusted_app but they are in global mount namespace - // when we umount for such process, that is a disaster! - bool is_zygote_child = is_zygote(get_current_cred()); - if (!is_zygote_child) { - pr_info("handle umount ignore non zygote child: %d\n", current->pid); - return 0; - } + // check old process's selinux context, if it is not zygote, ignore it! + // because some su apps may setuid to untrusted_app but they are in global mount namespace + // when we umount for such process, that is a disaster! + bool is_zygote_child = is_zygote(get_current_cred()); + if (!is_zygote_child) { + pr_info("handle umount ignore non zygote child: %d\n", current->pid); + return 0; + } #if __SULOG_GATE - ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); + ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); #endif #endif // #if defined(CONFIG_KSU_SUSFS) || !defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) - // umount the target mnt - pr_info("handle umount for uid: %d, pid: %d\n", new_uid, current->pid); + // umount the target mnt + pr_info("handle umount for uid: %d, pid: %d\n", new_uid, current->pid); - tw = kzalloc(sizeof(*tw), GFP_ATOMIC); - if (!tw) - return 0; + tw = kzalloc(sizeof(*tw), GFP_ATOMIC); + if (!tw) + return 0; - tw->old_cred = get_current_cred(); - tw->cb.func = umount_tw_func; + tw->old_cred = get_current_cred(); + tw->cb.func = umount_tw_func; - int err = task_work_add(current, &tw->cb, TWA_RESUME); - if (err) { - if (tw->old_cred) { - put_cred(tw->old_cred); - } - kfree(tw); - pr_warn("unmount add task_work failed\n"); - } + int err = task_work_add(current, &tw->cb, TWA_RESUME); + if (err) { + if (tw->old_cred) { + put_cred(tw->old_cred); + } + kfree(tw); + pr_warn("unmount add task_work failed\n"); + } - return 0; + return 0; } #endif // #if !defined(CONFIG_KSU_SUSFS) || !defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) void ksu_kernel_umount_init(void) { - if (ksu_register_feature_handler(&kernel_umount_handler)) { - pr_err("Failed to register kernel_umount feature handler\n"); - } + if (ksu_register_feature_handler(&kernel_umount_handler)) { + pr_err("Failed to register kernel_umount feature handler\n"); + } } void ksu_kernel_umount_exit(void) { - ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT); + ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT); } \ No newline at end of file diff --git a/kernel/kernel_umount.h b/kernel/kernel_umount.h index dcb05597..ba37ed59 100644 --- a/kernel/kernel_umount.h +++ b/kernel/kernel_umount.h @@ -15,9 +15,9 @@ int ksu_handle_umount(uid_t old_uid, uid_t new_uid); // for the umount list struct mount_entry { - char *umountable; - unsigned int flags; - struct list_head list; + char *umountable; + unsigned int flags; + struct list_head list; }; extern struct list_head mount_list; extern struct rw_semaphore mount_list_lock; diff --git a/kernel/kpm/compact.c b/kernel/kpm/compact.c index 5791db4f..e19094b2 100644 --- a/kernel/kpm/compact.c +++ b/kernel/kpm/compact.c @@ -31,70 +31,70 @@ static int sukisu_is_su_allow_uid(uid_t uid) { - return ksu_is_allow_uid_for_current(uid) ? 1 : 0; + return ksu_is_allow_uid_for_current(uid) ? 1 : 0; } static int sukisu_get_ap_mod_exclude(uid_t uid) { - return 0; /* Not supported */ + return 0; /* Not supported */ } static int sukisu_is_uid_should_umount(uid_t uid) { - return ksu_uid_should_umount(uid) ? 1 : 0; + return ksu_uid_should_umount(uid) ? 1 : 0; } static int sukisu_is_current_uid_manager(void) { - return is_manager(); + return is_manager(); } static uid_t sukisu_get_manager_uid(void) { - return ksu_manager_uid; + return ksu_manager_uid; } static void sukisu_set_manager_uid(uid_t uid, int force) { - if (force || ksu_manager_uid == -1) - ksu_manager_uid = uid; + if (force || ksu_manager_uid == -1) + ksu_manager_uid = uid; } struct CompactAddressSymbol { - const char *symbol_name; - void *addr; + const char *symbol_name; + void *addr; }; unsigned long sukisu_compact_find_symbol(const char *name); static struct CompactAddressSymbol address_symbol[] = { - { "kallsyms_lookup_name", &kallsyms_lookup_name }, - { "compact_find_symbol", &sukisu_compact_find_symbol }, - { "is_run_in_sukisu_ultra", (void *)1 }, - { "is_su_allow_uid", &sukisu_is_su_allow_uid }, - { "get_ap_mod_exclude", &sukisu_get_ap_mod_exclude }, - { "is_uid_should_umount", &sukisu_is_uid_should_umount }, - { "is_current_uid_manager", &sukisu_is_current_uid_manager }, - { "get_manager_uid", &sukisu_get_manager_uid }, - { "sukisu_set_manager_uid", &sukisu_set_manager_uid } + { "kallsyms_lookup_name", &kallsyms_lookup_name }, + { "compact_find_symbol", &sukisu_compact_find_symbol }, + { "is_run_in_sukisu_ultra", (void *)1 }, + { "is_su_allow_uid", &sukisu_is_su_allow_uid }, + { "get_ap_mod_exclude", &sukisu_get_ap_mod_exclude }, + { "is_uid_should_umount", &sukisu_is_uid_should_umount }, + { "is_current_uid_manager", &sukisu_is_current_uid_manager }, + { "get_manager_uid", &sukisu_get_manager_uid }, + { "sukisu_set_manager_uid", &sukisu_set_manager_uid } }; unsigned long sukisu_compact_find_symbol(const char* name) { - int i; - unsigned long addr; + int i; + unsigned long addr; - for (i = 0; i < (sizeof(address_symbol) / sizeof(struct CompactAddressSymbol)); i++) { - struct CompactAddressSymbol *symbol = &address_symbol[i]; - - if (strcmp(name, symbol->symbol_name) == 0) - return (unsigned long)symbol->addr; - } + for (i = 0; i < (sizeof(address_symbol) / sizeof(struct CompactAddressSymbol)); i++) { + struct CompactAddressSymbol *symbol = &address_symbol[i]; + + if (strcmp(name, symbol->symbol_name) == 0) + return (unsigned long)symbol->addr; + } - addr = kallsyms_lookup_name(name); - if (addr) - return addr; + addr = kallsyms_lookup_name(name); + if (addr) + return addr; - return 0; + return 0; } EXPORT_SYMBOL(sukisu_compact_find_symbol); diff --git a/kernel/kpm/kpm.c b/kernel/kpm/kpm.c index e806056e..ed9bd212 100644 --- a/kernel/kpm/kpm.c +++ b/kernel/kpm/kpm.c @@ -44,240 +44,240 @@ #ifndef NO_OPTIMIZE #if defined(__GNUC__) && !defined(__clang__) - #define NO_OPTIMIZE __attribute__((optimize("O0"))) + #define NO_OPTIMIZE __attribute__((optimize("O0"))) #elif defined(__clang__) - #define NO_OPTIMIZE __attribute__((optnone)) + #define NO_OPTIMIZE __attribute__((optnone)) #else - #define NO_OPTIMIZE + #define NO_OPTIMIZE #endif #endif noinline NO_OPTIMIZE void sukisu_kpm_load_module_path(const char *path, - const char *args, void *ptr, int *result) + const char *args, void *ptr, int *result) { - pr_info("kpm: Stub function called (sukisu_kpm_load_module_path). " - "path=%s args=%s ptr=%p\n", path, args, ptr); + pr_info("kpm: Stub function called (sukisu_kpm_load_module_path). " + "path=%s args=%s ptr=%p\n", path, args, ptr); - __asm__ volatile("nop"); + __asm__ volatile("nop"); } EXPORT_SYMBOL(sukisu_kpm_load_module_path); noinline NO_OPTIMIZE void sukisu_kpm_unload_module(const char *name, - void *ptr, int *result) + void *ptr, int *result) { - pr_info("kpm: Stub function called (sukisu_kpm_unload_module). " - "name=%s ptr=%p\n", name, ptr); + pr_info("kpm: Stub function called (sukisu_kpm_unload_module). " + "name=%s ptr=%p\n", name, ptr); - __asm__ volatile("nop"); + __asm__ volatile("nop"); } EXPORT_SYMBOL(sukisu_kpm_unload_module); noinline NO_OPTIMIZE void sukisu_kpm_num(int *result) { - pr_info("kpm: Stub function called (sukisu_kpm_num).\n"); + pr_info("kpm: Stub function called (sukisu_kpm_num).\n"); - __asm__ volatile("nop"); + __asm__ volatile("nop"); } EXPORT_SYMBOL(sukisu_kpm_num); noinline NO_OPTIMIZE void sukisu_kpm_info(const char *name, char *buf, int bufferSize, - int *size) + int *size) { - pr_info("kpm: Stub function called (sukisu_kpm_info). " - "name=%s buffer=%p\n", name, buf); + pr_info("kpm: Stub function called (sukisu_kpm_info). " + "name=%s buffer=%p\n", name, buf); - __asm__ volatile("nop"); + __asm__ volatile("nop"); } EXPORT_SYMBOL(sukisu_kpm_info); noinline NO_OPTIMIZE void sukisu_kpm_list(void *out, int bufferSize, - int *result) + int *result) { - pr_info("kpm: Stub function called (sukisu_kpm_list). " - "buffer=%p size=%d\n", out, bufferSize); + pr_info("kpm: Stub function called (sukisu_kpm_list). " + "buffer=%p size=%d\n", out, bufferSize); } EXPORT_SYMBOL(sukisu_kpm_list); noinline NO_OPTIMIZE void sukisu_kpm_control(const char *name, const char *args, long arg_len, - int *result) + int *result) { - pr_info("kpm: Stub function called (sukisu_kpm_control). " - "name=%p args=%p arg_len=%ld\n", name, args, arg_len); + pr_info("kpm: Stub function called (sukisu_kpm_control). " + "name=%p args=%p arg_len=%ld\n", name, args, arg_len); - __asm__ volatile("nop"); + __asm__ volatile("nop"); } EXPORT_SYMBOL(sukisu_kpm_control); noinline NO_OPTIMIZE void sukisu_kpm_version(char *buf, int bufferSize) { - pr_info("kpm: Stub function called (sukisu_kpm_version). " - "buffer=%p\n", buf); + pr_info("kpm: Stub function called (sukisu_kpm_version). " + "buffer=%p\n", buf); } EXPORT_SYMBOL(sukisu_kpm_version); noinline int sukisu_handle_kpm(unsigned long control_code, unsigned long arg1, unsigned long arg2, - unsigned long result_code) + unsigned long result_code) { - int res = -1; - if (control_code == SUKISU_KPM_LOAD) { - char kernel_load_path[256]; - char kernel_args_buffer[256]; + int res = -1; + if (control_code == SUKISU_KPM_LOAD) { + char kernel_load_path[256]; + char kernel_args_buffer[256]; - if (arg1 == 0) { - res = -EINVAL; - goto exit; - } + if (arg1 == 0) { + res = -EINVAL; + goto exit; + } - if (!ksu_access_ok(arg1, sizeof(kernel_load_path))) { - goto invalid_arg; - } - - strncpy_from_user((char *)&kernel_load_path, (const char *)arg1, sizeof(kernel_load_path)); - - if (arg2 != 0) { - if (!ksu_access_ok(arg2, sizeof(kernel_args_buffer))) { - goto invalid_arg; - } + if (!ksu_access_ok(arg1, sizeof(kernel_load_path))) { + goto invalid_arg; + } + + strncpy_from_user((char *)&kernel_load_path, (const char *)arg1, sizeof(kernel_load_path)); + + if (arg2 != 0) { + if (!ksu_access_ok(arg2, sizeof(kernel_args_buffer))) { + goto invalid_arg; + } - strncpy_from_user((char *)&kernel_args_buffer, (const char *)arg2, sizeof(kernel_args_buffer)); - } + strncpy_from_user((char *)&kernel_args_buffer, (const char *)arg2, sizeof(kernel_args_buffer)); + } - sukisu_kpm_load_module_path((const char *)&kernel_load_path, - (const char *)&kernel_args_buffer, NULL, &res); - } else if (control_code == SUKISU_KPM_UNLOAD) { - char kernel_name_buffer[256]; + sukisu_kpm_load_module_path((const char *)&kernel_load_path, + (const char *)&kernel_args_buffer, NULL, &res); + } else if (control_code == SUKISU_KPM_UNLOAD) { + char kernel_name_buffer[256]; - if (arg1 == 0) { - res = -EINVAL; - goto exit; - } + if (arg1 == 0) { + res = -EINVAL; + goto exit; + } - if (!ksu_access_ok(arg1, sizeof(kernel_name_buffer))) { - goto invalid_arg; - } - - strncpy_from_user((char *)&kernel_name_buffer, (const char *)arg1, sizeof(kernel_name_buffer)); - - sukisu_kpm_unload_module((const char *)&kernel_name_buffer, NULL, &res); - } else if (control_code == SUKISU_KPM_NUM) { - sukisu_kpm_num(&res); - } else if (control_code == SUKISU_KPM_INFO) { - char kernel_name_buffer[256]; - char buf[256]; - int size; + if (!ksu_access_ok(arg1, sizeof(kernel_name_buffer))) { + goto invalid_arg; + } + + strncpy_from_user((char *)&kernel_name_buffer, (const char *)arg1, sizeof(kernel_name_buffer)); + + sukisu_kpm_unload_module((const char *)&kernel_name_buffer, NULL, &res); + } else if (control_code == SUKISU_KPM_NUM) { + sukisu_kpm_num(&res); + } else if (control_code == SUKISU_KPM_INFO) { + char kernel_name_buffer[256]; + char buf[256]; + int size; - if (arg1 == 0 || arg2 == 0) { - res = -EINVAL; - goto exit; - } + if (arg1 == 0 || arg2 == 0) { + res = -EINVAL; + goto exit; + } - if (!ksu_access_ok(arg1, sizeof(kernel_name_buffer))) { - goto invalid_arg; - } - - strncpy_from_user((char *)&kernel_name_buffer, (const char __user *)arg1, sizeof(kernel_name_buffer)); - - sukisu_kpm_info((const char *)&kernel_name_buffer, (char *)&buf, sizeof(buf), &size); + if (!ksu_access_ok(arg1, sizeof(kernel_name_buffer))) { + goto invalid_arg; + } + + strncpy_from_user((char *)&kernel_name_buffer, (const char __user *)arg1, sizeof(kernel_name_buffer)); + + sukisu_kpm_info((const char *)&kernel_name_buffer, (char *)&buf, sizeof(buf), &size); - if (!ksu_access_ok(arg2, size)) { - goto invalid_arg; - } + if (!ksu_access_ok(arg2, size)) { + goto invalid_arg; + } - res = copy_to_user(arg2, &buf, size); + res = copy_to_user(arg2, &buf, size); - } else if (control_code == SUKISU_KPM_LIST) { - char buf[1024]; - int len = (int) arg2; + } else if (control_code == SUKISU_KPM_LIST) { + char buf[1024]; + int len = (int) arg2; - if (len <= 0) { - res = -EINVAL; - goto exit; - } + if (len <= 0) { + res = -EINVAL; + goto exit; + } - if (!ksu_access_ok(arg2, len)) { - goto invalid_arg; - } - - sukisu_kpm_list((char *)&buf, sizeof(buf), &res); + if (!ksu_access_ok(arg2, len)) { + goto invalid_arg; + } + + sukisu_kpm_list((char *)&buf, sizeof(buf), &res); - if (res > len) { - res = -ENOBUFS; - goto exit; - } + if (res > len) { + res = -ENOBUFS; + goto exit; + } - if (copy_to_user(arg1, &buf, len) != 0) - pr_info("kpm: Copy to user failed."); - - } else if (control_code == SUKISU_KPM_CONTROL) { - char kpm_name[KPM_NAME_LEN] = { 0 }; - char kpm_args[KPM_ARGS_LEN] = { 0 }; + if (copy_to_user(arg1, &buf, len) != 0) + pr_info("kpm: Copy to user failed."); + + } else if (control_code == SUKISU_KPM_CONTROL) { + char kpm_name[KPM_NAME_LEN] = { 0 }; + char kpm_args[KPM_ARGS_LEN] = { 0 }; - if (!ksu_access_ok(arg1, sizeof(kpm_name))) { - goto invalid_arg; - } + if (!ksu_access_ok(arg1, sizeof(kpm_name))) { + goto invalid_arg; + } - if (!ksu_access_ok(arg2, sizeof(kpm_args))) { - goto invalid_arg; - } + if (!ksu_access_ok(arg2, sizeof(kpm_args))) { + goto invalid_arg; + } - long name_len = strncpy_from_user((char *)&kpm_name, (const char __user *)arg1, sizeof(kpm_name)); - if (name_len <= 0) { - res = -EINVAL; - goto exit; - } + long name_len = strncpy_from_user((char *)&kpm_name, (const char __user *)arg1, sizeof(kpm_name)); + if (name_len <= 0) { + res = -EINVAL; + goto exit; + } - long arg_len = strncpy_from_user((char *)&kpm_args, (const char __user *)arg2, sizeof(kpm_args)); + long arg_len = strncpy_from_user((char *)&kpm_args, (const char __user *)arg2, sizeof(kpm_args)); - sukisu_kpm_control((const char *)&kpm_name, (const char *)&kpm_args, arg_len, &res); + sukisu_kpm_control((const char *)&kpm_name, (const char *)&kpm_args, arg_len, &res); - } else if (control_code == SUKISU_KPM_VERSION) { - char buffer[256] = {0}; + } else if (control_code == SUKISU_KPM_VERSION) { + char buffer[256] = {0}; - sukisu_kpm_version((char*) &buffer, sizeof(buffer)); + sukisu_kpm_version((char*) &buffer, sizeof(buffer)); - unsigned int outlen = (unsigned int) arg2; - int len = strlen(buffer); - if (len >= outlen) len = outlen - 1; - - res = copy_to_user(arg1, &buffer, len + 1); - } + unsigned int outlen = (unsigned int) arg2; + int len = strlen(buffer); + if (len >= outlen) len = outlen - 1; + + res = copy_to_user(arg1, &buffer, len + 1); + } exit: - if (copy_to_user(result_code, &res, sizeof(res)) != 0) - pr_info("kpm: Copy to user failed."); - - return 0; + if (copy_to_user(result_code, &res, sizeof(res)) != 0) + pr_info("kpm: Copy to user failed."); + + return 0; invalid_arg: - pr_err("kpm: invalid pointer detected! arg1: %px arg2: %px\n", (void *)arg1, (void *)arg2); - res = -EFAULT; - goto exit; + pr_err("kpm: invalid pointer detected! arg1: %px arg2: %px\n", (void *)arg1, (void *)arg2); + res = -EFAULT; + goto exit; } EXPORT_SYMBOL(sukisu_handle_kpm); int sukisu_is_kpm_control_code(unsigned long control_code) { - return (control_code >= CMD_KPM_CONTROL && - control_code <= CMD_KPM_CONTROL_MAX) ? 1 : 0; + return (control_code >= CMD_KPM_CONTROL && + control_code <= CMD_KPM_CONTROL_MAX) ? 1 : 0; } int do_kpm(void __user *arg) { - struct ksu_kpm_cmd cmd; + struct ksu_kpm_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("kpm: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("kpm: copy_from_user failed\n"); + return -EFAULT; + } - if (!ksu_access_ok(cmd.control_code, sizeof(int))) { - pr_err("kpm: invalid control_code pointer %px\n", (void *)cmd.control_code); - return -EFAULT; - } + if (!ksu_access_ok(cmd.control_code, sizeof(int))) { + pr_err("kpm: invalid control_code pointer %px\n", (void *)cmd.control_code); + return -EFAULT; + } - if (!ksu_access_ok(cmd.result_code, sizeof(int))) { - pr_err("kpm: invalid result_code pointer %px\n", (void *)cmd.result_code); - return -EFAULT; - } + if (!ksu_access_ok(cmd.result_code, sizeof(int))) { + pr_err("kpm: invalid result_code pointer %px\n", (void *)cmd.result_code); + return -EFAULT; + } - return sukisu_handle_kpm(cmd.control_code, cmd.arg1, cmd.arg2, cmd.result_code); + return sukisu_handle_kpm(cmd.control_code, cmd.arg1, cmd.arg2, cmd.result_code); } diff --git a/kernel/kpm/kpm.h b/kernel/kpm/kpm.h index 0d74664b..f229b0e6 100644 --- a/kernel/kpm/kpm.h +++ b/kernel/kpm/kpm.h @@ -5,10 +5,10 @@ #include struct ksu_kpm_cmd { - __aligned_u64 __user control_code; - __aligned_u64 __user arg1; - __aligned_u64 __user arg2; - __aligned_u64 __user result_code; + __aligned_u64 __user control_code; + __aligned_u64 __user arg1; + __aligned_u64 __user arg2; + __aligned_u64 __user result_code; }; int sukisu_handle_kpm(unsigned long control_code, unsigned long arg1, unsigned long arg2, unsigned long result_code); diff --git a/kernel/kpm/super_access.c b/kernel/kpm/super_access.c index 82c496dc..9c0d541d 100644 --- a/kernel/kpm/super_access.c +++ b/kernel/kpm/super_access.c @@ -36,154 +36,154 @@ #include "compact.h" struct DynamicStructMember { - const char *name; - size_t size; - size_t offset; + const char *name; + size_t size; + size_t offset; }; struct DynamicStructInfo { - const char *name; - size_t count; - size_t total_size; - struct DynamicStructMember *members; + const char *name; + size_t count; + size_t total_size; + struct DynamicStructMember *members; }; #define DYNAMIC_STRUCT_BEGIN(struct_name) \ - static struct DynamicStructMember struct_name##_members[] = { + static struct DynamicStructMember struct_name##_members[] = { #define DEFINE_MEMBER(struct_name, member) \ - { \ - .name = #member, \ - .size = sizeof(((struct struct_name *)0)->member), \ - .offset = offsetof(struct struct_name, member) \ - }, + { \ + .name = #member, \ + .size = sizeof(((struct struct_name *)0)->member), \ + .offset = offsetof(struct struct_name, member) \ + }, #define DYNAMIC_STRUCT_END(struct_name) \ - }; \ - static struct DynamicStructInfo struct_name##_info = { \ - .name = #struct_name, \ - .count = sizeof(struct_name##_members) / sizeof(struct DynamicStructMember), \ - .total_size = sizeof(struct struct_name), \ - .members = struct_name##_members \ - }; + }; \ + static struct DynamicStructInfo struct_name##_info = { \ + .name = #struct_name, \ + .count = sizeof(struct_name##_members) / sizeof(struct DynamicStructMember), \ + .total_size = sizeof(struct struct_name), \ + .members = struct_name##_members \ + }; DYNAMIC_STRUCT_BEGIN(mount) - DEFINE_MEMBER(mount, mnt_parent) - DEFINE_MEMBER(mount, mnt) - DEFINE_MEMBER(mount, mnt_id) - DEFINE_MEMBER(mount, mnt_group_id) - DEFINE_MEMBER(mount, mnt_expiry_mark) - DEFINE_MEMBER(mount, mnt_master) - DEFINE_MEMBER(mount, mnt_devname) + DEFINE_MEMBER(mount, mnt_parent) + DEFINE_MEMBER(mount, mnt) + DEFINE_MEMBER(mount, mnt_id) + DEFINE_MEMBER(mount, mnt_group_id) + DEFINE_MEMBER(mount, mnt_expiry_mark) + DEFINE_MEMBER(mount, mnt_master) + DEFINE_MEMBER(mount, mnt_devname) DYNAMIC_STRUCT_END(mount) DYNAMIC_STRUCT_BEGIN(vfsmount) - DEFINE_MEMBER(vfsmount, mnt_root) - DEFINE_MEMBER(vfsmount, mnt_sb) - DEFINE_MEMBER(vfsmount, mnt_flags) + DEFINE_MEMBER(vfsmount, mnt_root) + DEFINE_MEMBER(vfsmount, mnt_sb) + DEFINE_MEMBER(vfsmount, mnt_flags) DYNAMIC_STRUCT_END(vfsmount) DYNAMIC_STRUCT_BEGIN(mnt_namespace) - DEFINE_MEMBER(mnt_namespace, ns) - DEFINE_MEMBER(mnt_namespace, root) - DEFINE_MEMBER(mnt_namespace, seq) - DEFINE_MEMBER(mnt_namespace, mounts) + DEFINE_MEMBER(mnt_namespace, ns) + DEFINE_MEMBER(mnt_namespace, root) + DEFINE_MEMBER(mnt_namespace, seq) + DEFINE_MEMBER(mnt_namespace, mounts) #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) - DEFINE_MEMBER(mnt_namespace, count) + DEFINE_MEMBER(mnt_namespace, count) #endif DYNAMIC_STRUCT_END(mnt_namespace) #ifdef CONFIG_KPROBES DYNAMIC_STRUCT_BEGIN(kprobe) - DEFINE_MEMBER(kprobe, addr) - DEFINE_MEMBER(kprobe, symbol_name) - DEFINE_MEMBER(kprobe, offset) - DEFINE_MEMBER(kprobe, pre_handler) - DEFINE_MEMBER(kprobe, post_handler) + DEFINE_MEMBER(kprobe, addr) + DEFINE_MEMBER(kprobe, symbol_name) + DEFINE_MEMBER(kprobe, offset) + DEFINE_MEMBER(kprobe, pre_handler) + DEFINE_MEMBER(kprobe, post_handler) #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) - DEFINE_MEMBER(kprobe, fault_handler) + DEFINE_MEMBER(kprobe, fault_handler) #endif - DEFINE_MEMBER(kprobe, flags) + DEFINE_MEMBER(kprobe, flags) DYNAMIC_STRUCT_END(kprobe) #endif DYNAMIC_STRUCT_BEGIN(vm_area_struct) - DEFINE_MEMBER(vm_area_struct,vm_start) - DEFINE_MEMBER(vm_area_struct,vm_end) - DEFINE_MEMBER(vm_area_struct,vm_flags) - DEFINE_MEMBER(vm_area_struct,anon_vma) - DEFINE_MEMBER(vm_area_struct,vm_pgoff) - DEFINE_MEMBER(vm_area_struct,vm_file) - DEFINE_MEMBER(vm_area_struct,vm_private_data) + DEFINE_MEMBER(vm_area_struct,vm_start) + DEFINE_MEMBER(vm_area_struct,vm_end) + DEFINE_MEMBER(vm_area_struct,vm_flags) + DEFINE_MEMBER(vm_area_struct,anon_vma) + DEFINE_MEMBER(vm_area_struct,vm_pgoff) + DEFINE_MEMBER(vm_area_struct,vm_file) + DEFINE_MEMBER(vm_area_struct,vm_private_data) #ifdef CONFIG_ANON_VMA_NAME - DEFINE_MEMBER(vm_area_struct, anon_name) + DEFINE_MEMBER(vm_area_struct, anon_name) #endif - DEFINE_MEMBER(vm_area_struct, vm_ops) + DEFINE_MEMBER(vm_area_struct, vm_ops) DYNAMIC_STRUCT_END(vm_area_struct) DYNAMIC_STRUCT_BEGIN(vm_operations_struct) - DEFINE_MEMBER(vm_operations_struct, open) - DEFINE_MEMBER(vm_operations_struct, close) - DEFINE_MEMBER(vm_operations_struct, name) - DEFINE_MEMBER(vm_operations_struct, access) + DEFINE_MEMBER(vm_operations_struct, open) + DEFINE_MEMBER(vm_operations_struct, close) + DEFINE_MEMBER(vm_operations_struct, name) + DEFINE_MEMBER(vm_operations_struct, access) DYNAMIC_STRUCT_END(vm_operations_struct) DYNAMIC_STRUCT_BEGIN(netlink_kernel_cfg) - DEFINE_MEMBER(netlink_kernel_cfg, groups) - DEFINE_MEMBER(netlink_kernel_cfg, flags) - DEFINE_MEMBER(netlink_kernel_cfg, input) + DEFINE_MEMBER(netlink_kernel_cfg, groups) + DEFINE_MEMBER(netlink_kernel_cfg, flags) + DEFINE_MEMBER(netlink_kernel_cfg, input) #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - DEFINE_MEMBER(netlink_kernel_cfg, cb_mutex) + DEFINE_MEMBER(netlink_kernel_cfg, cb_mutex) #endif - DEFINE_MEMBER(netlink_kernel_cfg, bind) - DEFINE_MEMBER(netlink_kernel_cfg, unbind) + DEFINE_MEMBER(netlink_kernel_cfg, bind) + DEFINE_MEMBER(netlink_kernel_cfg, unbind) #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) - DEFINE_MEMBER(netlink_kernel_cfg, compare) + DEFINE_MEMBER(netlink_kernel_cfg, compare) #endif DYNAMIC_STRUCT_END(netlink_kernel_cfg) DYNAMIC_STRUCT_BEGIN(task_struct) - DEFINE_MEMBER(task_struct, pid) - DEFINE_MEMBER(task_struct, tgid) - DEFINE_MEMBER(task_struct, cred) - DEFINE_MEMBER(task_struct, real_cred) - DEFINE_MEMBER(task_struct, comm) - DEFINE_MEMBER(task_struct, parent) - DEFINE_MEMBER(task_struct, group_leader) - DEFINE_MEMBER(task_struct, mm) - DEFINE_MEMBER(task_struct, active_mm) + DEFINE_MEMBER(task_struct, pid) + DEFINE_MEMBER(task_struct, tgid) + DEFINE_MEMBER(task_struct, cred) + DEFINE_MEMBER(task_struct, real_cred) + DEFINE_MEMBER(task_struct, comm) + DEFINE_MEMBER(task_struct, parent) + DEFINE_MEMBER(task_struct, group_leader) + DEFINE_MEMBER(task_struct, mm) + DEFINE_MEMBER(task_struct, active_mm) #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) - DEFINE_MEMBER(task_struct, pids[PIDTYPE_PID].pid) + DEFINE_MEMBER(task_struct, pids[PIDTYPE_PID].pid) #else - DEFINE_MEMBER(task_struct, thread_pid) + DEFINE_MEMBER(task_struct, thread_pid) #endif - DEFINE_MEMBER(task_struct, files) - DEFINE_MEMBER(task_struct, seccomp) + DEFINE_MEMBER(task_struct, files) + DEFINE_MEMBER(task_struct, seccomp) #ifdef CONFIG_THREAD_INFO_IN_TASK - DEFINE_MEMBER(task_struct, thread_info) + DEFINE_MEMBER(task_struct, thread_info) #endif #ifdef CONFIG_CGROUPS - DEFINE_MEMBER(task_struct, cgroups) + DEFINE_MEMBER(task_struct, cgroups) #endif #ifdef CONFIG_SECURITY - DEFINE_MEMBER(task_struct, security) + DEFINE_MEMBER(task_struct, security) #endif - DEFINE_MEMBER(task_struct, thread) + DEFINE_MEMBER(task_struct, thread) DYNAMIC_STRUCT_END(task_struct) #define STRUCT_INFO(name) &(name##_info) static struct DynamicStructInfo *dynamic_struct_infos[] = { - STRUCT_INFO(mount), - STRUCT_INFO(vfsmount), - STRUCT_INFO(mnt_namespace), + STRUCT_INFO(mount), + STRUCT_INFO(vfsmount), + STRUCT_INFO(mnt_namespace), #ifdef CONFIG_KPROBES - STRUCT_INFO(kprobe), + STRUCT_INFO(kprobe), #endif - STRUCT_INFO(vm_area_struct), - STRUCT_INFO(vm_operations_struct), - STRUCT_INFO(netlink_kernel_cfg), - STRUCT_INFO(task_struct) + STRUCT_INFO(vm_area_struct), + STRUCT_INFO(vm_operations_struct), + STRUCT_INFO(netlink_kernel_cfg), + STRUCT_INFO(task_struct) }; /* @@ -192,21 +192,21 @@ static struct DynamicStructInfo *dynamic_struct_infos[] = { */ int sukisu_super_find_struct(const char *struct_name, size_t *out_size, int *out_members) { - for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) { - struct DynamicStructInfo *info = dynamic_struct_infos[i]; - - if (strcmp(struct_name, info->name) == 0) { - if (out_size) - *out_size = info->total_size; - - if (out_members) - *out_members = info->count; - - return 0; - } - } - - return -1; + for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) { + struct DynamicStructInfo *info = dynamic_struct_infos[i]; + + if (strcmp(struct_name, info->name) == 0) { + if (out_size) + *out_size = info->total_size; + + if (out_members) + *out_members = info->count; + + return 0; + } + } + + return -1; } EXPORT_SYMBOL(sukisu_super_find_struct); @@ -217,34 +217,34 @@ EXPORT_SYMBOL(sukisu_super_find_struct); * return -2 if member not defined */ int sukisu_super_access(const char *struct_name, const char *member_name, size_t *out_offset, - size_t *out_size) + size_t *out_size) { - for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) { - struct DynamicStructInfo *info = dynamic_struct_infos[i]; - - if (strcmp(struct_name, info->name) == 0) { - for (size_t i1 = 0; i1 < info->count; i1++) { - if (strcmp(info->members[i1].name, member_name) == 0) { - if (out_offset) - *out_offset = info->members[i].offset; - - if (out_size) - *out_size = info->members[i].size; - - return 0; - } - } - - return -2; - } - } - - return -1; + for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) { + struct DynamicStructInfo *info = dynamic_struct_infos[i]; + + if (strcmp(struct_name, info->name) == 0) { + for (size_t i1 = 0; i1 < info->count; i1++) { + if (strcmp(info->members[i1].name, member_name) == 0) { + if (out_offset) + *out_offset = info->members[i].offset; + + if (out_size) + *out_size = info->members[i].size; + + return 0; + } + } + + return -2; + } + } + + return -1; } EXPORT_SYMBOL(sukisu_super_access); #define DYNAMIC_CONTAINER_OF(offset, member_ptr) ({ \ - (offset != (size_t)-1) ? (void*)((char*)(member_ptr) - offset) : NULL; \ + (offset != (size_t)-1) ? (void*)((char*)(member_ptr) - offset) : NULL; \ }) /* @@ -254,27 +254,27 @@ EXPORT_SYMBOL(sukisu_super_access); * return -2 if target member not defined */ int sukisu_super_container_of(const char *struct_name, const char *member_name, void *ptr, - void **out_ptr) + void **out_ptr) { - if (ptr == NULL) - return -3; + if (ptr == NULL) + return -3; - for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) { - struct DynamicStructInfo *info = dynamic_struct_infos[i]; - - if (strcmp(struct_name, info->name) == 0) { - for (size_t i1 = 0; i1 < info->count; i1++) { - if (strcmp(info->members[i1].name, member_name) == 0) { - *out_ptr = (void *)DYNAMIC_CONTAINER_OF(info->members[i1].offset, ptr); - - return 0; - } - } - - return -2; - } - } - - return -1; + for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) { + struct DynamicStructInfo *info = dynamic_struct_infos[i]; + + if (strcmp(struct_name, info->name) == 0) { + for (size_t i1 = 0; i1 < info->count; i1++) { + if (strcmp(info->members[i1].name, member_name) == 0) { + *out_ptr = (void *)DYNAMIC_CONTAINER_OF(info->members[i1].offset, ptr); + + return 0; + } + } + + return -2; + } + } + + return -1; } EXPORT_SYMBOL(sukisu_super_container_of); diff --git a/kernel/kpm/super_access.h b/kernel/kpm/super_access.h index 4f02109d..dfd2bc54 100644 --- a/kernel/kpm/super_access.h +++ b/kernel/kpm/super_access.h @@ -8,8 +8,8 @@ extern int sukisu_super_find_struct(const char *struct_name, size_t *out_size, int *out_members); extern int sukisu_super_access(const char *struct_name, const char *member_name, size_t *out_offset, - size_t *out_size); + size_t *out_size); extern int sukisu_super_container_of(const char *struct_name, const char *member_name, void *ptr, - void **out_ptr); + void **out_ptr); #endif \ No newline at end of file diff --git a/kernel/ksu.c b/kernel/ksu.c index 59744781..e3244e52 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -39,11 +39,11 @@ void sukisu_custom_config_init(void) void sukisu_custom_config_exit(void) { - ksu_uid_exit(); - ksu_throne_comm_exit(); - ksu_dynamic_manager_exit(); + ksu_uid_exit(); + ksu_throne_comm_exit(); + ksu_dynamic_manager_exit(); #if __SULOG_GATE - ksu_sulog_exit(); + ksu_sulog_exit(); #endif } @@ -53,69 +53,69 @@ int __init kernelsu_init(void) UTS_RELEASE, UTS_MACHINE, KSU_VERSION); #ifdef CONFIG_KSU_DEBUG - pr_alert("*************************************************************"); - pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); - pr_alert("** **"); - pr_alert("** You are running KernelSU in DEBUG mode **"); - pr_alert("** **"); - pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); - pr_alert("*************************************************************"); + pr_alert("*************************************************************"); + pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); + pr_alert("** **"); + pr_alert("** You are running KernelSU in DEBUG mode **"); + pr_alert("** **"); + pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); + pr_alert("*************************************************************"); #endif - ksu_feature_init(); + ksu_feature_init(); - ksu_lsm_hook_init(); + ksu_lsm_hook_init(); - ksu_supercalls_init(); + ksu_supercalls_init(); - sukisu_custom_config_init(); + sukisu_custom_config_init(); - ksu_syscall_hook_manager_init(); + ksu_syscall_hook_manager_init(); - ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0); + ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0); - ksu_allowlist_init(); + ksu_allowlist_init(); - ksu_throne_tracker_init(); + ksu_throne_tracker_init(); #ifdef CONFIG_KSU_SUSFS - susfs_init(); + susfs_init(); #endif #if defined(CONFIG_KPROBES) && !defined(CONFIG_KSU_SUSFS) - ksu_ksud_init(); + ksu_ksud_init(); #endif #ifdef MODULE #ifndef CONFIG_KSU_DEBUG - kobject_del(&THIS_MODULE->mkobj.kobj); + kobject_del(&THIS_MODULE->mkobj.kobj); #endif #endif - return 0; + return 0; } extern void ksu_observer_exit(void); void kernelsu_exit(void) { - ksu_allowlist_exit(); + ksu_allowlist_exit(); - ksu_observer_exit(); + ksu_observer_exit(); - ksu_throne_tracker_exit(); + ksu_throne_tracker_exit(); - destroy_workqueue(ksu_workqueue); + destroy_workqueue(ksu_workqueue); #if defined(CONFIG_KPROBES) && !defined(CONFIG_KSU_SUSFS) - ksu_ksud_exit(); + ksu_ksud_exit(); #endif - ksu_syscall_hook_manager_exit(); + ksu_syscall_hook_manager_exit(); - sukisu_custom_config_exit(); + sukisu_custom_config_exit(); - ksu_supercalls_exit(); - - ksu_feature_exit(); + ksu_supercalls_exit(); + + ksu_feature_exit(); } module_init(kernelsu_init); diff --git a/kernel/ksu.h b/kernel/ksu.h index d3140509..23b778c7 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -28,17 +28,17 @@ extern bool ksu_uid_scanner_enabled; #define UID_SCANNER_OP_CLEAR_ENV 2 struct dynamic_manager_user_config { - unsigned int operation; - unsigned int size; - char hash[65]; + unsigned int operation; + unsigned int size; + char hash[65]; }; struct manager_list_info { - int count; - struct { - uid_t uid; - int signature_index; - } managers[2]; + int count; + struct { + uid_t uid; + int signature_index; + } managers[2]; }; bool ksu_queue_work(struct work_struct *work); @@ -48,16 +48,16 @@ void ksu_lsm_hook_init(void); #if 0 static inline int startswith(char *s, char *prefix) { - return strncmp(s, prefix, strlen(prefix)); + return strncmp(s, prefix, strlen(prefix)); } static inline int endswith(const char *s, const char *t) { - size_t slen = strlen(s); - size_t tlen = strlen(t); - if (tlen > slen) - return 1; - return strcmp(s + slen - tlen, t); + size_t slen = strlen(s); + size_t tlen = strlen(t); + if (tlen > slen) + return 1; + return strcmp(s + slen - tlen, t); } #endif diff --git a/kernel/ksud.c b/kernel/ksud.c index 4b1ff2c2..2dc11c76 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -40,27 +40,27 @@ bool ksu_module_mounted __read_mostly = false; bool ksu_boot_completed __read_mostly = false; static const char KERNEL_SU_RC[] = - "\n" + "\n" - "on post-fs-data\n" - " start logd\n" - // We should wait for the post-fs-data finish - " exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n" - "\n" + "on post-fs-data\n" + " start logd\n" + // We should wait for the post-fs-data finish + " exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n" + "\n" - "on nonencrypted\n" - " exec u:r:su:s0 root -- " KSUD_PATH " services\n" - "\n" + "on nonencrypted\n" + " exec u:r:su:s0 root -- " KSUD_PATH " services\n" + "\n" - "on property:vold.decrypt=trigger_restart_framework\n" - " exec u:r:su:s0 root -- " KSUD_PATH " services\n" - "\n" + "on property:vold.decrypt=trigger_restart_framework\n" + " exec u:r:su:s0 root -- " KSUD_PATH " services\n" + "\n" - "on property:sys.boot_completed=1\n" - " exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n" - "\n" + "on property:sys.boot_completed=1\n" + " exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n" + "\n" - "\n"; + "\n"; static void stop_vfs_read_hook(void); static void stop_execve_hook(void); @@ -83,22 +83,22 @@ static bool is_boot_phase = true; void on_post_fs_data(void) { - static bool done = false; - if (done) { - pr_info("on_post_fs_data already done\n"); - return; - } - done = true; - pr_info("on_post_fs_data!\n"); - ksu_load_allow_list(); - ksu_observer_init(); - // sanity check, this may influence the performance - stop_input_hook(); + static bool done = false; + if (done) { + pr_info("on_post_fs_data already done\n"); + return; + } + done = true; + pr_info("on_post_fs_data!\n"); + ksu_load_allow_list(); + ksu_observer_init(); + // sanity check, this may influence the performance + stop_input_hook(); - // End of boot state - is_boot_phase = false; + // End of boot state + is_boot_phase = false; - ksu_file_sid = ksu_get_ksu_file_sid(); + ksu_file_sid = ksu_get_ksu_file_sid(); pr_info("ksu_file sid: %d\n", ksu_file_sid); } @@ -106,73 +106,73 @@ extern void ext4_unregister_sysfs(struct super_block *sb); int nuke_ext4_sysfs(const char* mnt) { #ifdef CONFIG_EXT4_FS - struct path path; - int err = kern_path(mnt, 0, &path); - if (err) { - pr_err("nuke path err: %d\n", err); - return err; - } + struct path path; + int err = kern_path(mnt, 0, &path); + if (err) { + pr_err("nuke path err: %d\n", err); + return err; + } - struct super_block *sb = path.dentry->d_inode->i_sb; - const char *name = sb->s_type->name; - if (strcmp(name, "ext4") != 0) { - pr_info("nuke but module aren't mounted\n"); - path_put(&path); - return -EINVAL; - } + struct super_block *sb = path.dentry->d_inode->i_sb; + const char *name = sb->s_type->name; + if (strcmp(name, "ext4") != 0) { + pr_info("nuke but module aren't mounted\n"); + path_put(&path); + return -EINVAL; + } - ext4_unregister_sysfs(sb); - path_put(&path); + ext4_unregister_sysfs(sb); + path_put(&path); - return 0; + return 0; #endif } void on_module_mounted(void){ - pr_info("on_module_mounted!\n"); - ksu_module_mounted = true; + pr_info("on_module_mounted!\n"); + ksu_module_mounted = true; } void on_boot_completed(void){ - ksu_boot_completed = true; - pr_info("on_boot_completed!\n"); - track_throne(true); + ksu_boot_completed = true; + pr_info("on_boot_completed!\n"); + track_throne(true); } #ifndef CONFIG_KSU_SUSFS #define MAX_ARG_STRINGS 0x7FFFFFFF struct user_arg_ptr { #ifdef CONFIG_COMPAT - bool is_compat; + bool is_compat; #endif - union { - const char __user *const __user *native; + union { + const char __user *const __user *native; #ifdef CONFIG_COMPAT - const compat_uptr_t __user *compat; + const compat_uptr_t __user *compat; #endif - } ptr; + } ptr; }; #endif // #ifndef CONFIG_KSU_SUSFS static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) { - const char __user *native; + const char __user *native; #ifdef CONFIG_COMPAT - if (unlikely(argv.is_compat)) { - compat_uptr_t compat; + if (unlikely(argv.is_compat)) { + compat_uptr_t compat; - if (get_user(compat, argv.ptr.compat + nr)) - return ERR_PTR(-EFAULT); + if (get_user(compat, argv.ptr.compat + nr)) + return ERR_PTR(-EFAULT); - return compat_ptr(compat); - } + return compat_ptr(compat); + } #endif - if (get_user(native, argv.ptr.native + nr)) - return ERR_PTR(-EFAULT); + if (get_user(native, argv.ptr.native + nr)) + return ERR_PTR(-EFAULT); - return native; + return native; } /* @@ -186,160 +186,160 @@ static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) static int __maybe_unused count(struct user_arg_ptr argv, int max) { - int i = 0; + int i = 0; - if (argv.ptr.native != NULL) { - for (;;) { - const char __user *p = get_user_arg_ptr(argv, i); + if (argv.ptr.native != NULL) { + for (;;) { + const char __user *p = get_user_arg_ptr(argv, i); - if (!p) - break; + if (!p) + break; - if (IS_ERR(p)) - return -EFAULT; + if (IS_ERR(p)) + return -EFAULT; - if (i >= max) - return -E2BIG; - ++i; + if (i >= max) + return -E2BIG; + ++i; - if (fatal_signal_pending(current)) - return -ERESTARTNOHAND; - } - } - return i; + if (fatal_signal_pending(current)) + return -ERESTARTNOHAND; + } + } + return i; } static void on_post_fs_data_cbfun(struct callback_head *cb) { - on_post_fs_data(); + on_post_fs_data(); } static struct callback_head on_post_fs_data_cb = { .func = - on_post_fs_data_cbfun }; + on_post_fs_data_cbfun }; // IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, - struct user_arg_ptr *argv, - struct user_arg_ptr *envp, int *flags) + struct user_arg_ptr *argv, + struct user_arg_ptr *envp, int *flags) { #ifndef KSU_KPROBES_HOOK - if (!ksu_execveat_hook) { - return 0; - } + if (!ksu_execveat_hook) { + return 0; + } #endif - struct filename *filename; + struct filename *filename; - static const char app_process[] = "/system/bin/app_process"; - static bool first_app_process = true; + static const char app_process[] = "/system/bin/app_process"; + static bool first_app_process = true; - /* This applies to versions Android 10+ */ - static const char system_bin_init[] = "/system/bin/init"; - /* This applies to versions between Android 6 ~ 9 */ - static const char old_system_init[] = "/init"; - static bool init_second_stage_executed = false; + /* This applies to versions Android 10+ */ + static const char system_bin_init[] = "/system/bin/init"; + /* This applies to versions between Android 6 ~ 9 */ + static const char old_system_init[] = "/init"; + static bool init_second_stage_executed = false; - if (!filename_ptr) - return 0; + if (!filename_ptr) + return 0; - filename = *filename_ptr; - if (IS_ERR(filename)) { - return 0; - } + filename = *filename_ptr; + if (IS_ERR(filename)) { + return 0; + } - if (unlikely(!memcmp(filename->name, system_bin_init, - sizeof(system_bin_init) - 1) && - argv)) { - // /system/bin/init executed - int argc = count(*argv, MAX_ARG_STRINGS); - pr_info("/system/bin/init argc: %d\n", argc); - if (argc > 1 && !init_second_stage_executed) { - const char __user *p = get_user_arg_ptr(*argv, 1); - if (p && !IS_ERR(p)) { - char first_arg[16]; - ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); - pr_info("/system/bin/init first arg: %s\n", first_arg); - if (!strcmp(first_arg, "second_stage")) { - pr_info("/system/bin/init second_stage executed\n"); - apply_kernelsu_rules(); - init_second_stage_executed = true; - } - } else { - pr_err("/system/bin/init parse args err!\n"); - } - } - } else if (unlikely(!memcmp(filename->name, old_system_init, - sizeof(old_system_init) - 1) && - argv)) { - // /init executed - int argc = count(*argv, MAX_ARG_STRINGS); - pr_info("/init argc: %d\n", argc); - if (argc > 1 && !init_second_stage_executed) { - /* This applies to versions between Android 6 ~ 7 */ - const char __user *p = get_user_arg_ptr(*argv, 1); - if (p && !IS_ERR(p)) { - char first_arg[16]; - ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); - pr_info("/init first arg: %s\n", first_arg); - if (!strcmp(first_arg, "--second-stage")) { - pr_info("/init second_stage executed\n"); - apply_kernelsu_rules(); - init_second_stage_executed = true; - } - } else { - pr_err("/init parse args err!\n"); - } - } else if (argc == 1 && !init_second_stage_executed && envp) { - /* This applies to versions between Android 8 ~ 9 */ - int envc = count(*envp, MAX_ARG_STRINGS); - if (envc > 0) { - int n; - for (n = 1; n <= envc; n++) { - const char __user *p = get_user_arg_ptr(*envp, n); - if (!p || IS_ERR(p)) { - continue; - } - char env[256]; - // Reading environment variable strings from user space - if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0) - continue; - // Parsing environment variable names and values - char *env_name = env; - char *env_value = strchr(env, '='); - if (env_value == NULL) - continue; - // Replace equal sign with string terminator - *env_value = '\0'; - env_value++; - // Check if the environment variable name and value are matching - if (!strcmp(env_name, "INIT_SECOND_STAGE") && - (!strcmp(env_value, "1") || - !strcmp(env_value, "true"))) { - pr_info("/init second_stage executed\n"); - apply_kernelsu_rules(); - init_second_stage_executed = true; - } - } - } - } - } + if (unlikely(!memcmp(filename->name, system_bin_init, + sizeof(system_bin_init) - 1) && + argv)) { + // /system/bin/init executed + int argc = count(*argv, MAX_ARG_STRINGS); + pr_info("/system/bin/init argc: %d\n", argc); + if (argc > 1 && !init_second_stage_executed) { + const char __user *p = get_user_arg_ptr(*argv, 1); + if (p && !IS_ERR(p)) { + char first_arg[16]; + ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); + pr_info("/system/bin/init first arg: %s\n", first_arg); + if (!strcmp(first_arg, "second_stage")) { + pr_info("/system/bin/init second_stage executed\n"); + apply_kernelsu_rules(); + init_second_stage_executed = true; + } + } else { + pr_err("/system/bin/init parse args err!\n"); + } + } + } else if (unlikely(!memcmp(filename->name, old_system_init, + sizeof(old_system_init) - 1) && + argv)) { + // /init executed + int argc = count(*argv, MAX_ARG_STRINGS); + pr_info("/init argc: %d\n", argc); + if (argc > 1 && !init_second_stage_executed) { + /* This applies to versions between Android 6 ~ 7 */ + const char __user *p = get_user_arg_ptr(*argv, 1); + if (p && !IS_ERR(p)) { + char first_arg[16]; + ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); + pr_info("/init first arg: %s\n", first_arg); + if (!strcmp(first_arg, "--second-stage")) { + pr_info("/init second_stage executed\n"); + apply_kernelsu_rules(); + init_second_stage_executed = true; + } + } else { + pr_err("/init parse args err!\n"); + } + } else if (argc == 1 && !init_second_stage_executed && envp) { + /* This applies to versions between Android 8 ~ 9 */ + int envc = count(*envp, MAX_ARG_STRINGS); + if (envc > 0) { + int n; + for (n = 1; n <= envc; n++) { + const char __user *p = get_user_arg_ptr(*envp, n); + if (!p || IS_ERR(p)) { + continue; + } + char env[256]; + // Reading environment variable strings from user space + if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0) + continue; + // Parsing environment variable names and values + char *env_name = env; + char *env_value = strchr(env, '='); + if (env_value == NULL) + continue; + // Replace equal sign with string terminator + *env_value = '\0'; + env_value++; + // Check if the environment variable name and value are matching + if (!strcmp(env_name, "INIT_SECOND_STAGE") && + (!strcmp(env_value, "1") || + !strcmp(env_value, "true"))) { + pr_info("/init second_stage executed\n"); + apply_kernelsu_rules(); + init_second_stage_executed = true; + } + } + } + } + } - if (unlikely(first_app_process && !memcmp(filename->name, app_process, - sizeof(app_process) - 1))) { - first_app_process = false; - pr_info("exec app_process, /data prepared, second_stage: %d\n", - init_second_stage_executed); - struct task_struct *init_task; - rcu_read_lock(); - init_task = rcu_dereference(current->real_parent); - if (init_task) { - task_work_add(init_task, &on_post_fs_data_cb, TWA_RESUME); - } - rcu_read_unlock(); + if (unlikely(first_app_process && !memcmp(filename->name, app_process, + sizeof(app_process) - 1))) { + first_app_process = false; + pr_info("exec app_process, /data prepared, second_stage: %d\n", + init_second_stage_executed); + struct task_struct *init_task; + rcu_read_lock(); + init_task = rcu_dereference(current->real_parent); + if (init_task) { + task_work_add(init_task, &on_post_fs_data_cb, TWA_RESUME); + } + rcu_read_unlock(); - stop_execve_hook(); - } + stop_execve_hook(); + } - return 0; + return 0; } static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *); @@ -348,295 +348,295 @@ static struct file_operations fops_proxy; static ssize_t read_count_append = 0; static ssize_t read_proxy(struct file *file, char __user *buf, size_t count, - loff_t *pos) + loff_t *pos) { - bool first_read = file->f_pos == 0; - ssize_t ret = orig_read(file, buf, count, pos); - if (first_read) { - pr_info("read_proxy append %ld + %ld\n", ret, read_count_append); - ret += read_count_append; - } - return ret; + bool first_read = file->f_pos == 0; + ssize_t ret = orig_read(file, buf, count, pos); + if (first_read) { + pr_info("read_proxy append %ld + %ld\n", ret, read_count_append); + ret += read_count_append; + } + return ret; } static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to) { - bool first_read = iocb->ki_pos == 0; - ssize_t ret = orig_read_iter(iocb, to); - if (first_read) { - pr_info("read_iter_proxy append %ld + %ld\n", ret, read_count_append); - ret += read_count_append; - } - return ret; + bool first_read = iocb->ki_pos == 0; + ssize_t ret = orig_read_iter(iocb, to); + if (first_read) { + pr_info("read_iter_proxy append %ld + %ld\n", ret, read_count_append); + ret += read_count_append; + } + return ret; } static int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, - size_t *count_ptr, loff_t **pos) + size_t *count_ptr, loff_t **pos) { #ifndef KSU_KPROBES_HOOK - if (!ksu_vfs_read_hook) { - return 0; - } + if (!ksu_vfs_read_hook) { + return 0; + } #endif - struct file *file; - char __user *buf; - size_t count; + struct file *file; + char __user *buf; + size_t count; - if (strcmp(current->comm, "init")) { - // we are only interest in `init` process - return 0; - } + if (strcmp(current->comm, "init")) { + // we are only interest in `init` process + return 0; + } - file = *file_ptr; - if (IS_ERR(file)) { - return 0; - } + file = *file_ptr; + if (IS_ERR(file)) { + return 0; + } - if (!d_is_reg(file->f_path.dentry)) { - return 0; - } + if (!d_is_reg(file->f_path.dentry)) { + return 0; + } - const char *short_name = file->f_path.dentry->d_name.name; - if (strcmp(short_name, "atrace.rc")) { - // we are only interest `atrace.rc` file name file - return 0; - } - char path[256]; - char *dpath = d_path(&file->f_path, path, sizeof(path)); + const char *short_name = file->f_path.dentry->d_name.name; + if (strcmp(short_name, "atrace.rc")) { + // we are only interest `atrace.rc` file name file + return 0; + } + char path[256]; + char *dpath = d_path(&file->f_path, path, sizeof(path)); - if (IS_ERR(dpath)) { - return 0; - } + if (IS_ERR(dpath)) { + return 0; + } - if (strcmp(dpath, "/system/etc/init/atrace.rc")) { - return 0; - } + if (strcmp(dpath, "/system/etc/init/atrace.rc")) { + return 0; + } - // we only process the first read - static bool rc_inserted = false; - if (rc_inserted) { - // we don't need this kprobe, unregister it! - stop_vfs_read_hook(); - return 0; - } - rc_inserted = true; + // we only process the first read + static bool rc_inserted = false; + if (rc_inserted) { + // we don't need this kprobe, unregister it! + stop_vfs_read_hook(); + return 0; + } + rc_inserted = true; - // now we can sure that the init process is reading - // `/system/etc/init/atrace.rc` - buf = *buf_ptr; - count = *count_ptr; + // now we can sure that the init process is reading + // `/system/etc/init/atrace.rc` + buf = *buf_ptr; + count = *count_ptr; - size_t rc_count = strlen(KERNEL_SU_RC); + size_t rc_count = strlen(KERNEL_SU_RC); - pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath, - current->comm, count, rc_count); + pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath, + current->comm, count, rc_count); - if (count < rc_count) { - pr_err("count: %zu < rc_count: %zu\n", count, rc_count); - return 0; - } + if (count < rc_count) { + pr_err("count: %zu < rc_count: %zu\n", count, rc_count); + return 0; + } - size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count); - if (ret) { - pr_err("copy ksud.rc failed: %zu\n", ret); - return 0; - } + size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count); + if (ret) { + pr_err("copy ksud.rc failed: %zu\n", ret); + return 0; + } - // we've succeed to insert ksud.rc, now we need to proxy the read and modify the result! - // But, we can not modify the file_operations directly, because it's in read-only memory. - // We just replace the whole file_operations with a proxy one. - memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations)); - orig_read = file->f_op->read; - if (orig_read) { - fops_proxy.read = read_proxy; - } - orig_read_iter = file->f_op->read_iter; - if (orig_read_iter) { - fops_proxy.read_iter = read_iter_proxy; - } - // replace the file_operations - file->f_op = &fops_proxy; - read_count_append = rc_count; + // we've succeed to insert ksud.rc, now we need to proxy the read and modify the result! + // But, we can not modify the file_operations directly, because it's in read-only memory. + // We just replace the whole file_operations with a proxy one. + memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations)); + orig_read = file->f_op->read; + if (orig_read) { + fops_proxy.read = read_proxy; + } + orig_read_iter = file->f_op->read_iter; + if (orig_read_iter) { + fops_proxy.read_iter = read_iter_proxy; + } + // replace the file_operations + file->f_op = &fops_proxy; + read_count_append = rc_count; - *buf_ptr = buf + rc_count; - *count_ptr = count - rc_count; + *buf_ptr = buf + rc_count; + *count_ptr = count - rc_count; - return 0; + return 0; } int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, - size_t *count_ptr) + size_t *count_ptr) { - struct file *file = fget(fd); - if (!file) { - return 0; - } - int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL); - fput(file); - return result; + struct file *file = fget(fd); + if (!file) { + return 0; + } + int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL); + fput(file); + return result; } static unsigned int volumedown_pressed_count = 0; static bool is_volumedown_enough(unsigned int count) { - return count >= 3; + return count >= 3; } int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, - int *value) + int *value) { #ifndef KSU_KPROBES_HOOK - if (!ksu_input_hook) { - return 0; - } + if (!ksu_input_hook) { + return 0; + } #endif - if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) { - int val = *value; - pr_info("KEY_VOLUMEDOWN val: %d\n", val); - if (val && is_boot_phase) { - // key pressed, count it - volumedown_pressed_count += 1; - if (is_volumedown_enough(volumedown_pressed_count)) { - stop_input_hook(); - } - } - } + if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) { + int val = *value; + pr_info("KEY_VOLUMEDOWN val: %d\n", val); + if (val && is_boot_phase) { + // key pressed, count it + volumedown_pressed_count += 1; + if (is_volumedown_enough(volumedown_pressed_count)) { + stop_input_hook(); + } + } + } - return 0; + return 0; } bool ksu_is_safe_mode() { - static bool safe_mode = false; - if (safe_mode) { - // don't need to check again, userspace may call multiple times - return true; - } + static bool safe_mode = false; + if (safe_mode) { + // don't need to check again, userspace may call multiple times + return true; + } - // stop hook first! - stop_input_hook(); + // stop hook first! + stop_input_hook(); - pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count); - if (is_volumedown_enough(volumedown_pressed_count)) { - // pressed over 3 times - pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n"); - safe_mode = true; - return true; - } + pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count); + if (is_volumedown_enough(volumedown_pressed_count)) { + // pressed over 3 times + pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n"); + safe_mode = true; + return true; + } - return false; + return false; } #if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS) static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM1(real_regs); - const char __user *const __user *__argv = - (const char __user *const __user *)PT_REGS_PARM2(real_regs); - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct filename filename_in, *filename_p; - char path[32]; + struct pt_regs *real_regs = PT_REAL_REGS(regs); + const char __user **filename_user = + (const char **)&PT_REGS_PARM1(real_regs); + const char __user *const __user *__argv = + (const char __user *const __user *)PT_REGS_PARM2(real_regs); + struct user_arg_ptr argv = { .ptr.native = __argv }; + struct filename filename_in, *filename_p; + char path[32]; - if (!filename_user) - return 0; + if (!filename_user) + return 0; - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_nofault(path, *filename_user, 32); - filename_in.name = path; + memset(path, 0, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, 32); + filename_in.name = path; - filename_p = &filename_in; - return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, NULL); + filename_p = &filename_in; + return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, NULL); } static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - unsigned int fd = PT_REGS_PARM1(real_regs); - char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs); - size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs); + struct pt_regs *real_regs = PT_REAL_REGS(regs); + unsigned int fd = PT_REGS_PARM1(real_regs); + char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs); + size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs); - return ksu_handle_sys_read(fd, buf_ptr, count_ptr); + return ksu_handle_sys_read(fd, buf_ptr, count_ptr); } static int input_handle_event_handler_pre(struct kprobe *p, - struct pt_regs *regs) + struct pt_regs *regs) { - unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs); - unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs); - int *value = (int *)&PT_REGS_CCALL_PARM4(regs); - return ksu_handle_input_handle_event(type, code, value); + unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs); + unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs); + int *value = (int *)&PT_REGS_CCALL_PARM4(regs); + return ksu_handle_input_handle_event(type, code, value); } static struct kprobe execve_kp = { - .symbol_name = SYS_EXECVE_SYMBOL, - .pre_handler = sys_execve_handler_pre, + .symbol_name = SYS_EXECVE_SYMBOL, + .pre_handler = sys_execve_handler_pre, }; static struct kprobe vfs_read_kp = { - .symbol_name = SYS_READ_SYMBOL, - .pre_handler = sys_read_handler_pre, + .symbol_name = SYS_READ_SYMBOL, + .pre_handler = sys_read_handler_pre, }; static struct kprobe input_event_kp = { - .symbol_name = "input_event", - .pre_handler = input_handle_event_handler_pre, + .symbol_name = "input_event", + .pre_handler = input_handle_event_handler_pre, }; static void do_stop_vfs_read_hook(struct work_struct *work) { - unregister_kprobe(&vfs_read_kp); + unregister_kprobe(&vfs_read_kp); } static void do_stop_execve_hook(struct work_struct *work) { - unregister_kprobe(&execve_kp); + unregister_kprobe(&execve_kp); } static void do_stop_input_hook(struct work_struct *work) { - unregister_kprobe(&input_event_kp); + unregister_kprobe(&input_event_kp); } #endif static void stop_vfs_read_hook(void) { #if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS) - bool ret = schedule_work(&stop_vfs_read_work); - pr_info("unregister vfs_read kprobe: %d!\n", ret); + bool ret = schedule_work(&stop_vfs_read_work); + pr_info("unregister vfs_read kprobe: %d!\n", ret); #else - ksu_vfs_read_hook = false; - pr_info("stop vfs_read_hook\n"); + ksu_vfs_read_hook = false; + pr_info("stop vfs_read_hook\n"); #endif } static void stop_execve_hook(void) { #if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS) - bool ret = schedule_work(&stop_execve_hook_work); - pr_info("unregister execve kprobe: %d!\n", ret); + bool ret = schedule_work(&stop_execve_hook_work); + pr_info("unregister execve kprobe: %d!\n", ret); #else - ksu_execveat_hook = false; - pr_info("stop execve_hook\n"); + ksu_execveat_hook = false; + pr_info("stop execve_hook\n"); #endif } static void stop_input_hook(void) { - static bool input_hook_stopped = false; - if (input_hook_stopped) { - return; - } - input_hook_stopped = true; + static bool input_hook_stopped = false; + if (input_hook_stopped) { + return; + } + input_hook_stopped = true; #if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS) - bool ret = schedule_work(&stop_input_hook_work); - pr_info("unregister input kprobe: %d!\n", ret); + bool ret = schedule_work(&stop_input_hook_work); + pr_info("unregister input kprobe: %d!\n", ret); #else - ksu_input_hook = false; - pr_info("stop input_hook\n"); + ksu_input_hook = false; + pr_info("stop input_hook\n"); #endif } @@ -644,31 +644,31 @@ static void stop_input_hook(void) void ksu_ksud_init(void) { #if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS) - int ret; + int ret; - ret = register_kprobe(&execve_kp); - pr_info("ksud: execve_kp: %d\n", ret); + ret = register_kprobe(&execve_kp); + pr_info("ksud: execve_kp: %d\n", ret); - ret = register_kprobe(&vfs_read_kp); - pr_info("ksud: vfs_read_kp: %d\n", ret); + ret = register_kprobe(&vfs_read_kp); + pr_info("ksud: vfs_read_kp: %d\n", ret); - ret = register_kprobe(&input_event_kp); - pr_info("ksud: input_event_kp: %d\n", ret); + ret = register_kprobe(&input_event_kp); + pr_info("ksud: input_event_kp: %d\n", ret); - INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook); - INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook); - INIT_WORK(&stop_input_hook_work, do_stop_input_hook); + INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook); + INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook); + INIT_WORK(&stop_input_hook_work, do_stop_input_hook); #endif } void ksu_ksud_exit(void) { #if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS) - unregister_kprobe(&execve_kp); - // this should be done before unregister vfs_read_kp - // unregister_kprobe(&vfs_read_kp); - unregister_kprobe(&input_event_kp); + unregister_kprobe(&execve_kp); + // this should be done before unregister vfs_read_kp + // unregister_kprobe(&vfs_read_kp); + unregister_kprobe(&input_event_kp); #endif - is_boot_phase = false; - volumedown_pressed_count = 0; + is_boot_phase = false; + volumedown_pressed_count = 0; } diff --git a/kernel/ksud.h b/kernel/ksud.h index 14a43592..5dd6ece2 100644 --- a/kernel/ksud.h +++ b/kernel/ksud.h @@ -24,19 +24,19 @@ extern bool ksu_boot_completed; #define MAX_ARG_STRINGS 0x7FFFFFFF struct user_arg_ptr { #ifdef CONFIG_COMPAT - bool is_compat; + bool is_compat; #endif - union { - const char __user *const __user *native; + union { + const char __user *const __user *native; #ifdef CONFIG_COMPAT - const compat_uptr_t __user *compat; + const compat_uptr_t __user *compat; #endif - } ptr; + } ptr; }; int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, - struct user_arg_ptr *argv, - struct user_arg_ptr *envp, int *flags); + struct user_arg_ptr *argv, + struct user_arg_ptr *envp, int *flags); #endif // #ifdef CONFIG_KSU_SUSFS #endif diff --git a/kernel/lsm_hooks.c b/kernel/lsm_hooks.c index 931cf26a..495fe490 100644 --- a/kernel/lsm_hooks.c +++ b/kernel/lsm_hooks.c @@ -16,59 +16,59 @@ #include "manual_su.h" static int ksu_task_alloc(struct task_struct *task, - unsigned long clone_flags) + unsigned long clone_flags) { - ksu_try_escalate_for_uid(task_uid(task).val); - return 0; + ksu_try_escalate_for_uid(task_uid(task).val); + return 0; } #endif // kernel 4.4 and 4.9 -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ - defined(CONFIG_IS_HW_HISI) || \ - defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ + defined(CONFIG_IS_HW_HISI) || \ + defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred, - unsigned perm) + unsigned perm) { - if (init_session_keyring != NULL) { - return 0; - } - if (strcmp(current->comm, "init")) { - // we are only interested in `init` process - return 0; - } - init_session_keyring = cred->session_keyring; - pr_info("kernel_compat: got init_session_keyring\n"); - return 0; + if (init_session_keyring != NULL) { + return 0; + } + if (strcmp(current->comm, "init")) { + // we are only interested in `init` process + return 0; + } + init_session_keyring = cred->session_keyring; + pr_info("kernel_compat: got init_session_keyring\n"); + return 0; } #endif static struct security_hook_list ksu_hooks[] = { #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0) && defined(CONFIG_KSU_MANUAL_SU) - LSM_HOOK_INIT(task_alloc, ksu_task_alloc), + LSM_HOOK_INIT(task_alloc, ksu_task_alloc), #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ - defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) - LSM_HOOK_INIT(key_permission, ksu_key_permission) + defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) + LSM_HOOK_INIT(key_permission, ksu_key_permission) #endif }; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0) const struct lsm_id ksu_lsmid = { - .name = "ksu", - .id = 912, + .name = "ksu", + .id = 912, }; #endif void __init ksu_lsm_hook_init(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0) - // https://elixir.bootlin.com/linux/v6.8/source/include/linux/lsm_hooks.h#L120 - security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), &ksu_lsmid); + // https://elixir.bootlin.com/linux/v6.8/source/include/linux/lsm_hooks.h#L120 + security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), &ksu_lsmid); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) - security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), "ksu"); + security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), "ksu"); #else - // https://elixir.bootlin.com/linux/v4.10.17/source/include/linux/lsm_hooks.h#L1892 - security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks)); + // https://elixir.bootlin.com/linux/v4.10.17/source/include/linux/lsm_hooks.h#L1892 + security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks)); #endif } diff --git a/kernel/manager.h b/kernel/manager.h index 3cef7976..66ca31ad 100644 --- a/kernel/manager.h +++ b/kernel/manager.h @@ -15,43 +15,43 @@ extern int ksu_get_manager_signature_index(uid_t uid); static inline bool ksu_is_manager_uid_valid(void) { - return ksu_manager_uid != KSU_INVALID_UID; + return ksu_manager_uid != KSU_INVALID_UID; } #ifndef CONFIG_KSU_SUSFS 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_is_any_manager(current_uid().val) || + (ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val)); } #else static inline bool is_manager() { - return unlikely((ksu_manager_uid == current_uid().val % 100000) || - (ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val % 100000)); + return unlikely((ksu_manager_uid == current_uid().val % 100000) || + (ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val % 100000)); } #endif static inline uid_t ksu_get_manager_uid(void) { - return ksu_manager_uid; + return ksu_manager_uid; } #ifndef CONFIG_KSU_SUSFS static inline void ksu_set_manager_uid(uid_t uid) { - ksu_manager_uid = uid; + ksu_manager_uid = uid; } #else static inline void ksu_set_manager_uid(uid_t uid) { - ksu_manager_uid = uid % 100000; + ksu_manager_uid = uid % 100000; } #endif static inline void ksu_invalidate_manager_uid(void) { - ksu_manager_uid = KSU_INVALID_UID; + ksu_manager_uid = KSU_INVALID_UID; } int ksu_observer_init(void); diff --git a/kernel/manager_sign.h b/kernel/manager_sign.h index 3dc97d1f..f28d0cdc 100644 --- a/kernel/manager_sign.h +++ b/kernel/manager_sign.h @@ -10,8 +10,8 @@ #define EXPECTED_HASH_5EC1CFF "7e0c6d7278a3bb8e364e0fcba95afaf3666cf5ff3c245a3b63c8833bd0445cc4" // rsuntk/KernelSU -#define EXPECTED_SIZE_RSUNTK 0x396 -#define EXPECTED_HASH_RSUNTK "f415f4ed9435427e1fdf7f1fccd4dbc07b3d6b8751e4dbcec6f19671f427870b" +#define EXPECTED_SIZE_RSUNTK 0x396 +#define EXPECTED_HASH_RSUNTK "f415f4ed9435427e1fdf7f1fccd4dbc07b3d6b8751e4dbcec6f19671f427870b" // ShirkNeko/KernelSU #define EXPECTED_SIZE_SHIRKNEKO 0x35c @@ -26,8 +26,8 @@ #define EXPECTED_HASH_OTHER "0000000000000000000000000000000000000000000000000000000000000000" typedef struct { - unsigned size; - const char *sha256; + unsigned size; + const char *sha256; } apk_sign_key_t; #endif /* MANAGER_SIGN_H */ diff --git a/kernel/manual_su.c b/kernel/manual_su.c index e859a91c..cfff062b 100644 --- a/kernel/manual_su.c +++ b/kernel/manual_su.c @@ -29,330 +29,330 @@ static DEFINE_SPINLOCK(token_lock); static char* get_token_from_envp(void) { - struct mm_struct *mm; - char *envp_start, *envp_end; - char *env_ptr, *token = NULL; - unsigned long env_len; - char *env_copy = NULL; - - if (!current->mm) - return NULL; - - mm = current->mm; - - down_read(&mm->mmap_lock); - - envp_start = (char *)mm->env_start; - envp_end = (char *)mm->env_end; - env_len = envp_end - envp_start; - - if (env_len <= 0 || env_len > PAGE_SIZE * 32) { - up_read(&mm->mmap_lock); - return NULL; - } - - env_copy = kzalloc(env_len + 1, GFP_KERNEL); - if (!env_copy) { - up_read(&mm->mmap_lock); - return NULL; - } - - if (copy_from_user(env_copy, envp_start, env_len)) { - kfree(env_copy); - up_read(&mm->mmap_lock); - return NULL; - } - - up_read(&mm->mmap_lock); - - env_copy[env_len] = '\0'; - env_ptr = env_copy; - - while (env_ptr < env_copy + env_len) { - if (strncmp(env_ptr, KSU_TOKEN_ENV_NAME "=", strlen(KSU_TOKEN_ENV_NAME) + 1) == 0) { - char *token_start = env_ptr + strlen(KSU_TOKEN_ENV_NAME) + 1; - char *token_end = strchr(token_start, '\0'); - - if (token_end && (token_end - token_start) == KSU_TOKEN_LENGTH) { - token = kzalloc(KSU_TOKEN_LENGTH + 1, GFP_KERNEL); - if (token) { - memcpy(token, token_start, KSU_TOKEN_LENGTH); - token[KSU_TOKEN_LENGTH] = '\0'; - pr_info("manual_su: found auth token in environment\n"); - } - } - break; - } - - env_ptr += strlen(env_ptr) + 1; - } - - kfree(env_copy); - return token; + struct mm_struct *mm; + char *envp_start, *envp_end; + char *env_ptr, *token = NULL; + unsigned long env_len; + char *env_copy = NULL; + + if (!current->mm) + return NULL; + + mm = current->mm; + + down_read(&mm->mmap_lock); + + envp_start = (char *)mm->env_start; + envp_end = (char *)mm->env_end; + env_len = envp_end - envp_start; + + if (env_len <= 0 || env_len > PAGE_SIZE * 32) { + up_read(&mm->mmap_lock); + return NULL; + } + + env_copy = kzalloc(env_len + 1, GFP_KERNEL); + if (!env_copy) { + up_read(&mm->mmap_lock); + return NULL; + } + + if (copy_from_user(env_copy, envp_start, env_len)) { + kfree(env_copy); + up_read(&mm->mmap_lock); + return NULL; + } + + up_read(&mm->mmap_lock); + + env_copy[env_len] = '\0'; + env_ptr = env_copy; + + while (env_ptr < env_copy + env_len) { + if (strncmp(env_ptr, KSU_TOKEN_ENV_NAME "=", strlen(KSU_TOKEN_ENV_NAME) + 1) == 0) { + char *token_start = env_ptr + strlen(KSU_TOKEN_ENV_NAME) + 1; + char *token_end = strchr(token_start, '\0'); + + if (token_end && (token_end - token_start) == KSU_TOKEN_LENGTH) { + token = kzalloc(KSU_TOKEN_LENGTH + 1, GFP_KERNEL); + if (token) { + memcpy(token, token_start, KSU_TOKEN_LENGTH); + token[KSU_TOKEN_LENGTH] = '\0'; + pr_info("manual_su: found auth token in environment\n"); + } + } + break; + } + + env_ptr += strlen(env_ptr) + 1; + } + + kfree(env_copy); + return token; } static char* ksu_generate_auth_token(void) { - static char token_buffer[KSU_TOKEN_LENGTH + 1]; - unsigned long flags; - int i; - - ksu_cleanup_expired_tokens(); - - spin_lock_irqsave(&token_lock, flags); - - if (token_count >= MAX_TOKENS) { - for (i = 0; i < MAX_TOKENS - 1; i++) { - auth_tokens[i] = auth_tokens[i + 1]; - } - token_count = MAX_TOKENS - 1; - } - - for (i = 0; i < KSU_TOKEN_LENGTH; i++) { - u8 rand_byte; - get_random_bytes(&rand_byte, 1); - int char_type = rand_byte % 3; - if (char_type == 0) { - token_buffer[i] = 'A' + (rand_byte % 26); - } else if (char_type == 1) { - token_buffer[i] = 'a' + (rand_byte % 26); - } else { - token_buffer[i] = '0' + (rand_byte % 10); - } - } - + static char token_buffer[KSU_TOKEN_LENGTH + 1]; + unsigned long flags; + int i; + + ksu_cleanup_expired_tokens(); + + spin_lock_irqsave(&token_lock, flags); + + if (token_count >= MAX_TOKENS) { + for (i = 0; i < MAX_TOKENS - 1; i++) { + auth_tokens[i] = auth_tokens[i + 1]; + } + token_count = MAX_TOKENS - 1; + } + + for (i = 0; i < KSU_TOKEN_LENGTH; i++) { + u8 rand_byte; + get_random_bytes(&rand_byte, 1); + int char_type = rand_byte % 3; + if (char_type == 0) { + token_buffer[i] = 'A' + (rand_byte % 26); + } else if (char_type == 1) { + token_buffer[i] = 'a' + (rand_byte % 26); + } else { + token_buffer[i] = '0' + (rand_byte % 10); + } + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(auth_tokens[token_count].token, token_buffer, KSU_TOKEN_LENGTH + 1); + strscpy(auth_tokens[token_count].token, token_buffer, KSU_TOKEN_LENGTH + 1); #else - strlcpy(auth_tokens[token_count].token, token_buffer, KSU_TOKEN_LENGTH + 1); + strlcpy(auth_tokens[token_count].token, token_buffer, KSU_TOKEN_LENGTH + 1); #endif - auth_tokens[token_count].expire_time = jiffies + KSU_TOKEN_EXPIRE_TIME * HZ; - auth_tokens[token_count].used = false; - token_count++; - - spin_unlock_irqrestore(&token_lock, flags); - - pr_info("manual_su: generated new auth token (expires in %d seconds)\n", KSU_TOKEN_EXPIRE_TIME); - return token_buffer; + auth_tokens[token_count].expire_time = jiffies + KSU_TOKEN_EXPIRE_TIME * HZ; + auth_tokens[token_count].used = false; + token_count++; + + spin_unlock_irqrestore(&token_lock, flags); + + pr_info("manual_su: generated new auth token (expires in %d seconds)\n", KSU_TOKEN_EXPIRE_TIME); + return token_buffer; } static bool ksu_verify_auth_token(const char *token) { - unsigned long flags; - bool valid = false; - int i; - - if (!token || strlen(token) != KSU_TOKEN_LENGTH) { - return false; - } - - spin_lock_irqsave(&token_lock, flags); - - for (i = 0; i < token_count; i++) { - if (!auth_tokens[i].used && - time_before(jiffies, auth_tokens[i].expire_time) && - strcmp(auth_tokens[i].token, token) == 0) { - - auth_tokens[i].used = true; - valid = true; - pr_info("manual_su: auth token verified successfully\n"); - break; - } - } - - spin_unlock_irqrestore(&token_lock, flags); - - if (!valid) { - pr_warn("manual_su: invalid or expired auth token\n"); - } - - return valid; + unsigned long flags; + bool valid = false; + int i; + + if (!token || strlen(token) != KSU_TOKEN_LENGTH) { + return false; + } + + spin_lock_irqsave(&token_lock, flags); + + for (i = 0; i < token_count; i++) { + if (!auth_tokens[i].used && + time_before(jiffies, auth_tokens[i].expire_time) && + strcmp(auth_tokens[i].token, token) == 0) { + + auth_tokens[i].used = true; + valid = true; + pr_info("manual_su: auth token verified successfully\n"); + break; + } + } + + spin_unlock_irqrestore(&token_lock, flags); + + if (!valid) { + pr_warn("manual_su: invalid or expired auth token\n"); + } + + return valid; } static void ksu_cleanup_expired_tokens(void) { - unsigned long flags; - int i, j; - - spin_lock_irqsave(&token_lock, flags); - - for (i = 0; i < token_count; ) { - if (time_after(jiffies, auth_tokens[i].expire_time) || auth_tokens[i].used) { - for (j = i; j < token_count - 1; j++) { - auth_tokens[j] = auth_tokens[j + 1]; - } - token_count--; - pr_debug("manual_su: cleaned up expired/used token\n"); - } else { - i++; - } - } - - spin_unlock_irqrestore(&token_lock, flags); + unsigned long flags; + int i, j; + + spin_lock_irqsave(&token_lock, flags); + + for (i = 0; i < token_count; ) { + if (time_after(jiffies, auth_tokens[i].expire_time) || auth_tokens[i].used) { + for (j = i; j < token_count - 1; j++) { + auth_tokens[j] = auth_tokens[j + 1]; + } + token_count--; + pr_debug("manual_su: cleaned up expired/used token\n"); + } else { + i++; + } + } + + spin_unlock_irqrestore(&token_lock, flags); } static int handle_token_generation(struct manual_su_request *request) { - if (current_uid().val > 2000) { - pr_warn("manual_su: token generation denied for app UID %d\n", current_uid().val); - return -EPERM; - } - - char *new_token = ksu_generate_auth_token(); - if (!new_token) { - pr_err("manual_su: failed to generate token\n"); - return -ENOMEM; - } + if (current_uid().val > 2000) { + pr_warn("manual_su: token generation denied for app UID %d\n", current_uid().val); + return -EPERM; + } + + char *new_token = ksu_generate_auth_token(); + if (!new_token) { + pr_err("manual_su: failed to generate token\n"); + return -ENOMEM; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(request->token_buffer, new_token, KSU_TOKEN_LENGTH + 1); + strscpy(request->token_buffer, new_token, KSU_TOKEN_LENGTH + 1); #else - strlcpy(request->token_buffer, new_token, KSU_TOKEN_LENGTH + 1); + strlcpy(request->token_buffer, new_token, KSU_TOKEN_LENGTH + 1); #endif - pr_info("manual_su: auth token generated successfully\n"); - return 0; + pr_info("manual_su: auth token generated successfully\n"); + return 0; } static int handle_escalation_request(struct manual_su_request *request) { - uid_t target_uid = request->target_uid; - pid_t target_pid = request->target_pid; - struct task_struct *tsk; - - rcu_read_lock(); - tsk = pid_task(find_vpid(target_pid), PIDTYPE_PID); - if (!tsk || ksu_task_is_dead(tsk)) { - rcu_read_unlock(); - pr_err("cmd_su: PID %d is invalid or dead\n", target_pid); - return -ESRCH; - } - rcu_read_unlock(); - - if (current_uid().val == 0 || is_manager() || ksu_is_allow_uid_for_current(current_uid().val)) - goto allowed; + uid_t target_uid = request->target_uid; + pid_t target_pid = request->target_pid; + struct task_struct *tsk; + + rcu_read_lock(); + tsk = pid_task(find_vpid(target_pid), PIDTYPE_PID); + if (!tsk || ksu_task_is_dead(tsk)) { + rcu_read_unlock(); + pr_err("cmd_su: PID %d is invalid or dead\n", target_pid); + return -ESRCH; + } + rcu_read_unlock(); + + if (current_uid().val == 0 || is_manager() || ksu_is_allow_uid_for_current(current_uid().val)) + goto allowed; - char *env_token = get_token_from_envp(); - if (!env_token) { - pr_warn("manual_su: no auth token found in environment\n"); - return -EACCES; - } - - bool token_valid = ksu_verify_auth_token(env_token); - kfree(env_token); - - if (!token_valid) { - pr_warn("manual_su: token verification failed\n"); - return -EACCES; - } + char *env_token = get_token_from_envp(); + if (!env_token) { + pr_warn("manual_su: no auth token found in environment\n"); + return -EACCES; + } + + bool token_valid = ksu_verify_auth_token(env_token); + kfree(env_token); + + if (!token_valid) { + pr_warn("manual_su: token verification failed\n"); + return -EACCES; + } allowed: - current_verified = true; - escape_to_root_for_cmd_su(target_uid, target_pid); - return 0; + current_verified = true; + escape_to_root_for_cmd_su(target_uid, target_pid); + return 0; } static int handle_add_pending_request(struct manual_su_request *request) { - uid_t target_uid = request->target_uid; - - if (!is_current_verified()) { - pr_warn("manual_su: add_pending denied, not verified\n"); - return -EPERM; - } + uid_t target_uid = request->target_uid; + + if (!is_current_verified()) { + pr_warn("manual_su: add_pending denied, not verified\n"); + return -EPERM; + } - add_pending_root(target_uid); - current_verified = false; - pr_info("manual_su: pending root added for UID %d\n", target_uid); - return 0; + add_pending_root(target_uid); + current_verified = false; + pr_info("manual_su: pending root added for UID %d\n", target_uid); + return 0; } int ksu_handle_manual_su_request(int option, struct manual_su_request *request) { - if (!request) { - pr_err("manual_su: invalid request pointer\n"); - return -EINVAL; - } + if (!request) { + pr_err("manual_su: invalid request pointer\n"); + return -EINVAL; + } - switch (option) { - case MANUAL_SU_OP_GENERATE_TOKEN: - pr_info("manual_su: handling token generation request\n"); - return handle_token_generation(request); + switch (option) { + case MANUAL_SU_OP_GENERATE_TOKEN: + pr_info("manual_su: handling token generation request\n"); + return handle_token_generation(request); - case MANUAL_SU_OP_ESCALATE: - pr_info("manual_su: handling escalation request for UID %d, PID %d\n", - request->target_uid, request->target_pid); - return handle_escalation_request(request); - - case MANUAL_SU_OP_ADD_PENDING: - pr_info("manual_su: handling add pending request for UID %d\n", request->target_uid); - return handle_add_pending_request(request); - - default: - pr_err("manual_su: unknown option %d\n", option); - return -EINVAL; - } + case MANUAL_SU_OP_ESCALATE: + pr_info("manual_su: handling escalation request for UID %d, PID %d\n", + request->target_uid, request->target_pid); + return handle_escalation_request(request); + + case MANUAL_SU_OP_ADD_PENDING: + pr_info("manual_su: handling add pending request for UID %d\n", request->target_uid); + return handle_add_pending_request(request); + + default: + pr_err("manual_su: unknown option %d\n", option); + return -EINVAL; + } } static bool is_current_verified(void) { - return current_verified; + return current_verified; } bool is_pending_root(uid_t uid) { - for (int i = 0; i < pending_cnt; i++) { - if (pending_uids[i].uid == uid) { - pending_uids[i].use_count++; - pending_uids[i].remove_calls++; - return true; - } - } - return false; + for (int i = 0; i < pending_cnt; i++) { + if (pending_uids[i].uid == uid) { + pending_uids[i].use_count++; + pending_uids[i].remove_calls++; + return true; + } + } + return false; } void remove_pending_root(uid_t uid) { - for (int i = 0; i < pending_cnt; i++) { - if (pending_uids[i].uid == uid) { - pending_uids[i].remove_calls++; + for (int i = 0; i < pending_cnt; i++) { + if (pending_uids[i].uid == uid) { + pending_uids[i].remove_calls++; - if (pending_uids[i].remove_calls >= REMOVE_DELAY_CALLS) { - pending_uids[i] = pending_uids[--pending_cnt]; - pr_info("pending_root: removed UID %d after %d calls\n", uid, REMOVE_DELAY_CALLS); - ksu_temp_revoke_root_once(uid); - } else { - pr_info("pending_root: UID %d remove_call=%d (<%d)\n", - uid, pending_uids[i].remove_calls, REMOVE_DELAY_CALLS); - } - return; - } - } + if (pending_uids[i].remove_calls >= REMOVE_DELAY_CALLS) { + pending_uids[i] = pending_uids[--pending_cnt]; + pr_info("pending_root: removed UID %d after %d calls\n", uid, REMOVE_DELAY_CALLS); + ksu_temp_revoke_root_once(uid); + } else { + pr_info("pending_root: UID %d remove_call=%d (<%d)\n", + uid, pending_uids[i].remove_calls, REMOVE_DELAY_CALLS); + } + return; + } + } } static void add_pending_root(uid_t uid) { - if (pending_cnt >= MAX_PENDING) { - pr_warn("pending_root: cache full\n"); - return; - } - for (int i = 0; i < pending_cnt; i++) { - if (pending_uids[i].uid == uid) { - pending_uids[i].use_count = 0; - pending_uids[i].remove_calls = 0; - return; - } - } - pending_uids[pending_cnt++] = (struct pending_uid){uid, 0}; - ksu_temp_grant_root_once(uid); - pr_info("pending_root: cached UID %d\n", uid); + if (pending_cnt >= MAX_PENDING) { + pr_warn("pending_root: cache full\n"); + return; + } + for (int i = 0; i < pending_cnt; i++) { + if (pending_uids[i].uid == uid) { + pending_uids[i].use_count = 0; + pending_uids[i].remove_calls = 0; + return; + } + } + pending_uids[pending_cnt++] = (struct pending_uid){uid, 0}; + ksu_temp_grant_root_once(uid); + pr_info("pending_root: cached UID %d\n", uid); } void ksu_try_escalate_for_uid(uid_t uid) { - if (!is_pending_root(uid)) - return; - - pr_info("pending_root: UID=%d temporarily allowed\n", uid); - remove_pending_root(uid); + if (!is_pending_root(uid)) + return; + + pr_info("pending_root: UID=%d temporarily allowed\n", uid); + remove_pending_root(uid); } diff --git a/kernel/manual_su.h b/kernel/manual_su.h index ae8af6e6..ffb1ed4d 100644 --- a/kernel/manual_su.h +++ b/kernel/manual_su.h @@ -25,21 +25,21 @@ #define MANUAL_SU_OP_ADD_PENDING 2 struct pending_uid { - uid_t uid; - int use_count; - int remove_calls; + uid_t uid; + int use_count; + int remove_calls; }; struct manual_su_request { - uid_t target_uid; - pid_t target_pid; - char token_buffer[KSU_TOKEN_LENGTH + 1]; + uid_t target_uid; + pid_t target_pid; + char token_buffer[KSU_TOKEN_LENGTH + 1]; }; struct ksu_token_entry { - char token[KSU_TOKEN_LENGTH + 1]; - unsigned long expire_time; - bool used; + char token[KSU_TOKEN_LENGTH + 1]; + unsigned long expire_time; + bool used; }; int ksu_handle_manual_su_request(int option, struct manual_su_request *request); diff --git a/kernel/pkg_observer.c b/kernel/pkg_observer.c index b4d752a5..188d1dfd 100644 --- a/kernel/pkg_observer.c +++ b/kernel/pkg_observer.c @@ -15,11 +15,11 @@ #define MASK_SYSTEM (FS_CREATE | FS_MOVE | FS_EVENT_ON_CHILD) struct watch_dir { - const char *path; - u32 mask; - struct path kpath; - struct inode *inode; - struct fsnotify_mark *mark; + const char *path; + u32 mask; + struct path kpath; + struct inode *inode; + struct fsnotify_mark *mark; }; static struct fsnotify_group *g; @@ -27,132 +27,132 @@ static struct fsnotify_group *g; #include "pkg_observer_defs.h" // KSU_DECL_FSNOTIFY_OPS static KSU_DECL_FSNOTIFY_OPS(ksu_handle_generic_event) { - if (!file_name || (mask & FS_ISDIR)) - return 0; + if (!file_name || (mask & FS_ISDIR)) + return 0; - if (ksu_fname_len(file_name) == 13 && - !memcmp(ksu_fname_arg(file_name), "packages.list", 13)) { - pr_info("packages.list detected: %d\n", mask); - if (ksu_uid_scanner_enabled) { - ksu_request_userspace_scan(); - } - track_throne(false); - } - return 0; + if (ksu_fname_len(file_name) == 13 && + !memcmp(ksu_fname_arg(file_name), "packages.list", 13)) { + pr_info("packages.list detected: %d\n", mask); + if (ksu_uid_scanner_enabled) { + ksu_request_userspace_scan(); + } + track_throne(false); + } + return 0; } static const struct fsnotify_ops ksu_ops = { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - .handle_inode_event = ksu_handle_generic_event, + .handle_inode_event = ksu_handle_generic_event, #else - .handle_event = ksu_handle_generic_event, + .handle_event = ksu_handle_generic_event, #endif }; static void __maybe_unused m_free(struct fsnotify_mark *m) { - if (m) { - kfree(m); - } + if (m) { + kfree(m); + } } static int add_mark_on_inode(struct inode *inode, u32 mask, - struct fsnotify_mark **out) + struct fsnotify_mark **out) { - struct fsnotify_mark *m; - int ret; + struct fsnotify_mark *m; + int ret; - m = kzalloc(sizeof(*m), GFP_KERNEL); - if (!m) - return -ENOMEM; + m = kzalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return -ENOMEM; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) - fsnotify_init_mark(m, g); - m->mask = mask; - ret = fsnotify_add_inode_mark(m, inode, 0); + fsnotify_init_mark(m, g); + m->mask = mask; + ret = fsnotify_add_inode_mark(m, inode, 0); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) - fsnotify_init_mark(m, g); - m->mask = mask; - ret = fsnotify_add_mark(m, inode, NULL, 0); + fsnotify_init_mark(m, g); + m->mask = mask; + ret = fsnotify_add_mark(m, inode, NULL, 0); #else - fsnotify_init_mark(m, g, m_free); - m->mask = mask; - ret = fsnotify_add_mark(m, g, inode, NULL, 0); + fsnotify_init_mark(m, g, m_free); + m->mask = mask; + ret = fsnotify_add_mark(m, g, inode, NULL, 0); #endif - if (ret < 0) { - fsnotify_put_mark(m); - return ret; - } + if (ret < 0) { + fsnotify_put_mark(m); + return ret; + } - *out = m; - return 0; + *out = m; + return 0; } static int watch_one_dir(struct watch_dir *wd) { - int ret = kern_path(wd->path, LOOKUP_FOLLOW, &wd->kpath); - if (ret) { - pr_info("path not ready: %s (%d)\n", wd->path, ret); - return ret; - } - wd->inode = d_inode(wd->kpath.dentry); - ihold(wd->inode); + int ret = kern_path(wd->path, LOOKUP_FOLLOW, &wd->kpath); + if (ret) { + pr_info("path not ready: %s (%d)\n", wd->path, ret); + return ret; + } + wd->inode = d_inode(wd->kpath.dentry); + ihold(wd->inode); - ret = add_mark_on_inode(wd->inode, wd->mask, &wd->mark); - if (ret) { - pr_err("Add mark failed for %s (%d)\n", wd->path, ret); - path_put(&wd->kpath); - iput(wd->inode); - wd->inode = NULL; - return ret; - } - pr_info("watching %s\n", wd->path); - return 0; + ret = add_mark_on_inode(wd->inode, wd->mask, &wd->mark); + if (ret) { + pr_err("Add mark failed for %s (%d)\n", wd->path, ret); + path_put(&wd->kpath); + iput(wd->inode); + wd->inode = NULL; + return ret; + } + pr_info("watching %s\n", wd->path); + return 0; } static void unwatch_one_dir(struct watch_dir *wd) { - if (wd->mark) { - fsnotify_destroy_mark(wd->mark, g); - fsnotify_put_mark(wd->mark); - wd->mark = NULL; - } - if (wd->inode) { - iput(wd->inode); - wd->inode = NULL; - } - if (wd->kpath.dentry) { - path_put(&wd->kpath); - memset(&wd->kpath, 0, sizeof(wd->kpath)); - } + if (wd->mark) { + fsnotify_destroy_mark(wd->mark, g); + fsnotify_put_mark(wd->mark); + wd->mark = NULL; + } + if (wd->inode) { + iput(wd->inode); + wd->inode = NULL; + } + if (wd->kpath.dentry) { + path_put(&wd->kpath); + memset(&wd->kpath, 0, sizeof(wd->kpath)); + } } static struct watch_dir g_watch = { - .path = "/data/system", - .mask = MASK_SYSTEM + .path = "/data/system", + .mask = MASK_SYSTEM }; int ksu_observer_init(void) { - int ret = 0; + int ret = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) - g = fsnotify_alloc_group(&ksu_ops, 0); + g = fsnotify_alloc_group(&ksu_ops, 0); #else - g = fsnotify_alloc_group(&ksu_ops); + g = fsnotify_alloc_group(&ksu_ops); #endif - if (IS_ERR(g)) - return PTR_ERR(g); + if (IS_ERR(g)) + return PTR_ERR(g); - ret = watch_one_dir(&g_watch); - pr_info("%s done.\n", __func__); - return 0; + ret = watch_one_dir(&g_watch); + pr_info("%s done.\n", __func__); + return 0; } void ksu_observer_exit(void) { - unwatch_one_dir(&g_watch); - fsnotify_put_group(g); - pr_info("%s: done.\n", __func__); + unwatch_one_dir(&g_watch); + fsnotify_put_group(g); + pr_info("%s: done.\n", __func__); } \ No newline at end of file diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index 4c6ced98..07a8bee7 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -138,14 +138,14 @@ void apply_kernelsu_rules(void) // Allow system server kill su process ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid"); ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill"); - + #ifdef CONFIG_KSU_SUSFS - // Allow umount in zygote process without installing zygisk - ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount"); - susfs_set_priv_app_sid(); - susfs_set_init_sid(); - susfs_set_ksu_sid(); - susfs_set_zygote_sid(); + // Allow umount in zygote process without installing zygisk + ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount"); + susfs_set_priv_app_sid(); + susfs_set_init_sid(); + susfs_set_ksu_sid(); + susfs_set_zygote_sid(); #endif mutex_unlock(&ksu_rules); } @@ -175,7 +175,7 @@ struct sepol_data { }; static int get_object(char *buf, char __user *user_object, size_t buf_sz, - char **object) + char **object) { if (!user_object) { *object = ALL; @@ -190,7 +190,7 @@ static int get_object(char *buf, char __user *user_object, size_t buf_sz, return 0; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ !defined(KSU_COMPAT_USE_SELINUX_STATE) extern int avc_ss_reset(u32 seqno); #else @@ -199,7 +199,7 @@ extern int avc_ss_reset(struct selinux_avc *avc, u32 seqno); // reset avc cache table, otherwise the new rules will not take effect if already denied static void reset_avc_cache(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ !defined(KSU_COMPAT_USE_SELINUX_STATE) avc_ss_reset(0); selnl_notify_policyload(0); @@ -248,25 +248,25 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char *s, *t, *c, *p; if (get_object(src_buf, (void __user *)data.sepol1, - sizeof(src_buf), &s) < 0) { + sizeof(src_buf), &s) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } if (get_object(tgt_buf, (void __user *)data.sepol2, - sizeof(tgt_buf), &t) < 0) { + sizeof(tgt_buf), &t) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } if (get_object(cls_buf, (void __user *)data.sepol3, - sizeof(cls_buf), &c) < 0) { + sizeof(cls_buf), &c) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } if (get_object(perm_buf, (void __user *)data.sepol4, - sizeof(perm_buf), &p) < 0) { + sizeof(perm_buf), &p) < 0) { pr_err("sepol: copy perm failed.\n"); goto exit; } @@ -298,27 +298,27 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char *s, *t, *c; if (get_object(src_buf, (void __user *)data.sepol1, - sizeof(src_buf), &s) < 0) { + sizeof(src_buf), &s) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } if (get_object(tgt_buf, (void __user *)data.sepol2, - sizeof(tgt_buf), &t) < 0) { + sizeof(tgt_buf), &t) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } if (get_object(cls_buf, (void __user *)data.sepol3, - sizeof(cls_buf), &c) < 0) { + sizeof(cls_buf), &c) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } if (strncpy_from_user(operation, (void __user *)data.sepol4, - sizeof(operation)) < 0) { + sizeof(operation)) < 0) { pr_err("sepol: copy operation failed.\n"); goto exit; } if (strncpy_from_user(perm_set, (void __user *)data.sepol5, - sizeof(perm_set)) < 0) { + sizeof(perm_set)) < 0) { pr_err("sepol: copy perm_set failed.\n"); goto exit; } @@ -340,7 +340,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char src[MAX_SEPOL_LEN]; if (strncpy_from_user(src, (void __user *)data.sepol1, - sizeof(src)) < 0) { + sizeof(src)) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } @@ -363,12 +363,12 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char attr[MAX_SEPOL_LEN]; if (strncpy_from_user(type, (void __user *)data.sepol1, - sizeof(type)) < 0) { + sizeof(type)) < 0) { pr_err("sepol: copy type failed.\n"); goto exit; } if (strncpy_from_user(attr, (void __user *)data.sepol2, - sizeof(attr)) < 0) { + sizeof(attr)) < 0) { pr_err("sepol: copy attr failed.\n"); goto exit; } @@ -390,7 +390,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char attr[MAX_SEPOL_LEN]; if (strncpy_from_user(attr, (void __user *)data.sepol1, - sizeof(attr)) < 0) { + sizeof(attr)) < 0) { pr_err("sepol: copy attr failed.\n"); goto exit; } @@ -409,22 +409,22 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char object[MAX_SEPOL_LEN]; if (strncpy_from_user(src, (void __user *)data.sepol1, - sizeof(src)) < 0) { + sizeof(src)) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } if (strncpy_from_user(tgt, (void __user *)data.sepol2, - sizeof(tgt)) < 0) { + sizeof(tgt)) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } if (strncpy_from_user(cls, (void __user *)data.sepol3, - sizeof(cls)) < 0) { + sizeof(cls)) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } if (strncpy_from_user(default_type, (void __user *)data.sepol4, - sizeof(default_type)) < 0) { + sizeof(default_type)) < 0) { pr_err("sepol: copy default_type failed.\n"); goto exit; } @@ -433,8 +433,8 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) real_object = NULL; } else { if (strncpy_from_user(object, - (void __user *)data.sepol5, - sizeof(object)) < 0) { + (void __user *)data.sepol5, + sizeof(object)) < 0) { pr_err("sepol: copy object failed.\n"); goto exit; } @@ -454,22 +454,22 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char default_type[MAX_SEPOL_LEN]; if (strncpy_from_user(src, (void __user *)data.sepol1, - sizeof(src)) < 0) { + sizeof(src)) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } if (strncpy_from_user(tgt, (void __user *)data.sepol2, - sizeof(tgt)) < 0) { + sizeof(tgt)) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } if (strncpy_from_user(cls, (void __user *)data.sepol3, - sizeof(cls)) < 0) { + sizeof(cls)) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } if (strncpy_from_user(default_type, (void __user *)data.sepol4, - sizeof(default_type)) < 0) { + sizeof(default_type)) < 0) { pr_err("sepol: copy default_type failed.\n"); goto exit; } @@ -492,17 +492,17 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char path[MAX_SEPOL_LEN]; char context[MAX_SEPOL_LEN]; if (strncpy_from_user(name, (void __user *)data.sepol1, - sizeof(name)) < 0) { + sizeof(name)) < 0) { pr_err("sepol: copy name failed.\n"); goto exit; } if (strncpy_from_user(path, (void __user *)data.sepol2, - sizeof(path)) < 0) { + sizeof(path)) < 0) { pr_err("sepol: copy path failed.\n"); goto exit; } if (strncpy_from_user(context, (void __user *)data.sepol3, - sizeof(context)) < 0) { + sizeof(context)) < 0) { pr_err("sepol: copy context failed.\n"); goto exit; } diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 04a7b5ed..ad0ecfab 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -82,7 +82,7 @@ bool getenforce(void) return __is_selinux_enforcing(); } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \ !defined(KSU_COMPAT_HAS_CURRENT_SID) /* * get the subjective security ID of the current task @@ -197,81 +197,81 @@ u32 susfs_priv_app_sid = 0; static inline void susfs_set_sid(const char *secctx_name, u32 *out_sid) { - int err; - - if (!secctx_name || !out_sid) { - pr_err("secctx_name || out_sid is NULL\n"); - return; - } + int err; + + if (!secctx_name || !out_sid) { + pr_err("secctx_name || out_sid is NULL\n"); + return; + } - err = security_secctx_to_secid(secctx_name, strlen(secctx_name), - out_sid); - if (err) { - pr_err("failed setting sid for '%s', err: %d\n", secctx_name, err); - return; - } - pr_info("sid '%u' is set for secctx_name '%s'\n", *out_sid, secctx_name); + err = security_secctx_to_secid(secctx_name, strlen(secctx_name), + out_sid); + if (err) { + pr_err("failed setting sid for '%s', err: %d\n", secctx_name, err); + return; + } + pr_info("sid '%u' is set for secctx_name '%s'\n", *out_sid, secctx_name); } bool susfs_is_sid_equal(void *sec, u32 sid2) { - struct task_security_struct *tsec = (struct task_security_struct *)sec; - if (!tsec) { - return false; - } - return tsec->sid == sid2; + struct task_security_struct *tsec = (struct task_security_struct *)sec; + if (!tsec) { + return false; + } + return tsec->sid == sid2; } u32 susfs_get_sid_from_name(const char *secctx_name) { - u32 out_sid = 0; - int err; - - if (!secctx_name) { - pr_err("secctx_name is NULL\n"); - return 0; - } - err = security_secctx_to_secid(secctx_name, strlen(secctx_name), - &out_sid); - if (err) { - pr_err("failed getting sid from secctx_name: %s, err: %d\n", secctx_name, err); - return 0; - } - return out_sid; + u32 out_sid = 0; + int err; + + if (!secctx_name) { + pr_err("secctx_name is NULL\n"); + return 0; + } + err = security_secctx_to_secid(secctx_name, strlen(secctx_name), + &out_sid); + if (err) { + pr_err("failed getting sid from secctx_name: %s, err: %d\n", secctx_name, err); + return 0; + } + return out_sid; } u32 susfs_get_current_sid(void) { - return current_sid(); + return current_sid(); } void susfs_set_zygote_sid(void) { - susfs_set_sid(KERNEL_ZYGOTE_DOMAIN, &susfs_zygote_sid); + susfs_set_sid(KERNEL_ZYGOTE_DOMAIN, &susfs_zygote_sid); } bool susfs_is_current_zygote_domain(void) { - return unlikely(current_sid() == susfs_zygote_sid); + return unlikely(current_sid() == susfs_zygote_sid); } void susfs_set_ksu_sid(void) { - susfs_set_sid(KERNEL_SU_DOMAIN, &susfs_ksu_sid); + susfs_set_sid(KERNEL_SU_DOMAIN, &susfs_ksu_sid); } bool susfs_is_current_ksu_domain(void) { - return unlikely(current_sid() == susfs_ksu_sid); + return unlikely(current_sid() == susfs_ksu_sid); } void susfs_set_init_sid(void) { - susfs_set_sid(KERNEL_INIT_DOMAIN, &susfs_init_sid); + susfs_set_sid(KERNEL_INIT_DOMAIN, &susfs_init_sid); } bool susfs_is_current_init_domain(void) { - return unlikely(current_sid() == susfs_init_sid); + return unlikely(current_sid() == susfs_init_sid); } void susfs_set_priv_app_sid(void) { - susfs_set_sid(KERNEL_PRIV_APP_DOMAIN, &susfs_priv_app_sid); + susfs_set_sid(KERNEL_PRIV_APP_DOMAIN, &susfs_priv_app_sid); } #endif diff --git a/kernel/selinux/selinux.h b/kernel/selinux/selinux.h index 8f110f15..a77a1da4 100644 --- a/kernel/selinux/selinux.h +++ b/kernel/selinux/selinux.h @@ -5,7 +5,7 @@ #include "linux/version.h" #include "linux/cred.h" -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || \ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || \ defined(KSU_COMPAT_HAS_SELINUX_STATE) #define KSU_COMPAT_USE_SELINUX_STATE #endif diff --git a/kernel/selinux/sepolicy.c b/kernel/selinux/sepolicy.c index 0a6abec2..2d9660b9 100644 --- a/kernel/selinux/sepolicy.c +++ b/kernel/selinux/sepolicy.c @@ -19,16 +19,16 @@ static struct avtab_node *get_avtab_node(struct policydb *db, struct avtab_extended_perms *xperms); static bool add_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *p, int effect, bool invert); + const char *c, const char *p, int effect, bool invert); static void add_rule_raw(struct policydb *db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls, struct perm_datum *perm, int effect, bool invert); static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - uint16_t low, uint16_t high, int effect, - bool invert); + struct type_datum *tgt, struct class_datum *cls, + uint16_t low, uint16_t high, int effect, + bool invert); static bool add_xperm_rule(struct policydb *db, const char *s, const char *t, const char *c, const char *range, int effect, bool invert); @@ -37,8 +37,8 @@ static bool add_type_rule(struct policydb *db, const char *s, const char *t, const char *c, const char *d, int effect); static bool add_filename_trans(struct policydb *db, const char *s, - const char *t, const char *c, const char *d, - const char *o); + const char *t, const char *c, const char *d, + const char *o); static bool add_genfscon(struct policydb *db, const char *fs_name, const char *path, const char *context); @@ -52,7 +52,7 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, struct type_datum *attr); static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr); + const char *attr); ////////////////////////////////////////////////////// // Implementation @@ -62,18 +62,18 @@ static bool add_typeattribute(struct policydb *db, const char *type, // rules #define strip_av(effect, invert) ((effect == AVTAB_AUDITDENY) == !invert) -#define ksu_hash_for_each(node_ptr, n_slot, cur) \ - int i; \ - for (i = 0; i < n_slot; ++i) \ +#define ksu_hash_for_each(node_ptr, n_slot, cur) \ + int i; \ + for (i = 0; i < n_slot; ++i) \ for (cur = node_ptr[i]; cur; cur = cur->next) // htable is a struct instead of pointer above 5.8.0: // https://elixir.bootlin.com/linux/v5.8-rc1/source/security/selinux/ss/symtab.h #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -#define ksu_hashtab_for_each(htab, cur) \ +#define ksu_hashtab_for_each(htab, cur) \ ksu_hash_for_each(htab.htable, htab.size, cur) #else -#define ksu_hashtab_for_each(htab, cur) \ +#define ksu_hashtab_for_each(htab, cur) \ ksu_hash_for_each(htab->htable, htab->size, cur) #endif @@ -84,7 +84,7 @@ static bool add_typeattribute(struct policydb *db, const char *type, #define symtab_insert(s, name, datum) hashtab_insert((s)->table, name, datum) #endif -#define avtab_for_each(avtab, cur) \ +#define avtab_for_each(avtab, cur) \ ksu_hash_for_each(avtab.htable, avtab.nslot, cur); static struct avtab_node *get_avtab_node(struct policydb *db, @@ -99,8 +99,8 @@ static struct avtab_node *get_avtab_node(struct policydb *db, node = avtab_search_node(&db->te_avtab, key); while (node) { if ((node->datum.u.xperms->specified == - xperms->specified) && - (node->datum.u.xperms->driver == xperms->driver)) { + xperms->specified) && + (node->datum.u.xperms->driver == xperms->driver)) { match = true; break; } @@ -115,9 +115,9 @@ static struct avtab_node *get_avtab_node(struct policydb *db, if (!node) { struct avtab_datum avdatum = {}; /* - * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for - * others. Initialize the data accordingly. - */ + * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for + * others. Initialize the data accordingly. + */ if (key->specified & AVTAB_XPERMS) { avdatum.u.xperms = xperms; } else { @@ -133,7 +133,7 @@ static struct avtab_node *get_avtab_node(struct policydb *db, grow_size += sizeof(u8); grow_size += sizeof(u8); grow_size += sizeof(u32) * - ARRAY_SIZE(avdatum.u.xperms->perms.p); + ARRAY_SIZE(avdatum.u.xperms->perms.p); } db->len += grow_size; } @@ -142,7 +142,7 @@ static struct avtab_node *get_avtab_node(struct policydb *db, } static bool add_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *p, int effect, bool invert) + const char *c, const char *p, int effect, bool invert) { struct type_datum *src = NULL, *tgt = NULL; struct class_datum *cls = NULL; @@ -202,8 +202,8 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, ksu_hashtab_for_each(db->p_types.table, node) { add_rule_raw(db, - (struct type_datum *)node->datum, - tgt, cls, perm, effect, invert); + (struct type_datum *)node->datum, + tgt, cls, perm, effect, invert); }; } else { ksu_hashtab_for_each(db->p_types.table, node) @@ -212,7 +212,7 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, (struct type_datum *)(node->datum); if (type->attribute) { add_rule_raw(db, type, tgt, cls, perm, - effect, invert); + effect, invert); } }; } @@ -222,8 +222,8 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, ksu_hashtab_for_each(db->p_types.table, node) { add_rule_raw(db, src, - (struct type_datum *)node->datum, - cls, perm, effect, invert); + (struct type_datum *)node->datum, + cls, perm, effect, invert); }; } else { ksu_hashtab_for_each(db->p_types.table, node) @@ -232,7 +232,7 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, (struct type_datum *)(node->datum); if (type->attribute) { add_rule_raw(db, src, type, cls, perm, - effect, invert); + effect, invert); } }; } @@ -241,8 +241,8 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, ksu_hashtab_for_each(db->p_classes.table, node) { add_rule_raw(db, src, tgt, - (struct class_datum *)node->datum, perm, - effect, invert); + (struct class_datum *)node->datum, perm, + effect, invert); } } else { struct avtab_key key; @@ -275,9 +275,9 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, #define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f))) static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - uint16_t low, uint16_t high, int effect, - bool invert) + struct type_datum *tgt, struct class_datum *cls, + uint16_t low, uint16_t high, int effect, + bool invert) { if (src == NULL) { struct hashtab_node *node; @@ -331,7 +331,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, int i; if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { for (i = ioctl_driver(low); i <= ioctl_driver(high); - ++i) { + ++i) { if (invert) xperm_clear(i, xperms.perms.p); else @@ -497,8 +497,8 @@ static const struct hashtab_key_params filenametr_key_params = { #endif static bool add_filename_trans(struct policydb *db, const char *s, - const char *t, const char *c, const char *d, - const char *o) + const char *t, const char *c, const char *d, + const char *o) { struct type_datum *src, *tgt, *def; struct class_datum *cls; @@ -553,16 +553,16 @@ static bool add_filename_trans(struct policydb *db, const char *s, if (trans == NULL) { trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), - 1, GFP_ATOMIC); + 1, GFP_ATOMIC); struct filename_trans_key *new_key = (struct filename_trans_key *)kzalloc(sizeof(*new_key), - GFP_ATOMIC); + GFP_ATOMIC); *new_key = key; new_key->name = kstrdup(key.name, GFP_ATOMIC); trans->next = last; trans->otype = def->value; hashtab_insert(&db->filename_trans, new_key, trans, - filenametr_key_params); + filenametr_key_params); } db->compat_filename_trans_count++; @@ -579,7 +579,7 @@ static bool add_filename_trans(struct policydb *db, const char *s, if (trans == NULL) { trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), - 1, GFP_ATOMIC); + 1, GFP_ATOMIC); if (!trans) { pr_err("add_filename_trans: Failed to alloc datum\n"); return false; @@ -598,7 +598,7 @@ static bool add_filename_trans(struct policydb *db, const char *s, } return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) == - 0; + 0; #endif } @@ -635,7 +635,7 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr) u32 value = ++db->p_types.nprim; type = (struct type_datum *)kzalloc(sizeof(struct type_datum), - GFP_ATOMIC); + GFP_ATOMIC); if (!type) { pr_err("add_type: alloc type_datum failed.\n"); return false; @@ -659,8 +659,8 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) struct ebitmap *new_type_attr_map_array = ksu_realloc(db->type_attr_map_array, - value * sizeof(struct ebitmap), - (value - 1) * sizeof(struct ebitmap)); + value * sizeof(struct ebitmap), + (value - 1) * sizeof(struct ebitmap)); if (!new_type_attr_map_array) { pr_err("add_type: alloc type_attr_map_array failed\n"); @@ -669,8 +669,8 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr) struct type_datum **new_type_val_to_struct = ksu_realloc(db->type_val_to_struct, - sizeof(*db->type_val_to_struct) * value, - sizeof(*db->type_val_to_struct) * (value - 1)); + sizeof(*db->type_val_to_struct) * value, + sizeof(*db->type_val_to_struct) * (value - 1)); if (!new_type_val_to_struct) { pr_err("add_type: alloc type_val_to_struct failed\n"); @@ -679,8 +679,8 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr) char **new_val_to_name_types = ksu_realloc(db->sym_val_to_name[SYM_TYPES], - sizeof(char *) * value, - sizeof(char *) * (value - 1)); + sizeof(char *) * value, + sizeof(char *) * (value - 1)); if (!new_val_to_name_types) { pr_err("add_type: alloc val_to_name failed\n"); return false; @@ -809,7 +809,7 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr) old_elem = flex_array_get(db->type_attr_map_array, j); if (old_elem) flex_array_put(new_type_attr_map_array, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); + GFP_ATOMIC | __GFP_ZERO); } for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) { @@ -880,7 +880,7 @@ static bool set_type_state(struct policydb *db, const char *type_name, { type = (struct type_datum *)(node->datum); if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) + permissive)) pr_info("Could not set bit in permissive map\n"); }; } else { @@ -891,7 +891,7 @@ static bool set_type_state(struct policydb *db, const char *type_name, return false; } if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) { + permissive)) { pr_info("Could not set bit in permissive map\n"); return false; } @@ -909,7 +909,7 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, * HISI_SELINUX_EBITMAP_RO is Huawei's unique features. */ struct ebitmap *sattr = &db->type_attr_map[type->value - 1], - HISI_SELINUX_EBITMAP_RO; + HISI_SELINUX_EBITMAP_RO; #else struct ebitmap *sattr = flex_array_get(db->type_attr_map_array, type->value - 1); @@ -925,8 +925,8 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, for (n = cls->constraints; n; n = n->next) { for (e = n->expr; e; e = e->next) { if (e->expr_type == CEXPR_NAMES && - ebitmap_get_bit(&e->type_names->types, - attr->value - 1)) { + ebitmap_get_bit(&e->type_names->types, + attr->value - 1)) { ebitmap_set_bit(&e->names, type->value - 1, 1); } @@ -936,7 +936,7 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, } static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr) + const char *attr) { struct type_datum *type_d = symtab_search(&db->p_types, type); if (type_d == NULL) { @@ -995,19 +995,19 @@ bool ksu_exists(struct policydb *db, const char *type) // Access vector rules bool ksu_allow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, false); } bool ksu_deny(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, true); } bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) + const char *cls, const char *perm) { return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITALLOW, false); } @@ -1019,24 +1019,24 @@ bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt, // Extended permissions access vector rules bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) + const char *cls, const char *range) { return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, - false); + false); } bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt, const char *cls, const char *range) { return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, - false); + false); } bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt, const char *cls, const char *range) { return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, - false); + false); } // Type rules @@ -1051,13 +1051,13 @@ bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt, } bool ksu_type_change(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def) + const char *cls, const char *def) { return add_type_rule(db, src, tgt, cls, def, AVTAB_CHANGE); } bool ksu_type_member(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def) + const char *cls, const char *def) { return add_type_rule(db, src, tgt, cls, def, AVTAB_MEMBER); } diff --git a/kernel/selinux/sepolicy.h b/kernel/selinux/sepolicy.h index fd062ce6..f9a1cd1d 100644 --- a/kernel/selinux/sepolicy.h +++ b/kernel/selinux/sepolicy.h @@ -15,32 +15,32 @@ bool ksu_exists(struct policydb *db, const char *type); // Access vector rules bool ksu_allow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); + const char *cls, const char *perm); bool ksu_deny(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); + const char *cls, const char *perm); bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); + const char *cls, const char *perm); bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); + const char *cls, const char *perm); // Extended permissions access vector rules bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range); + const char *cls, const char *range); bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range); + const char *cls, const char *range); bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range); + const char *cls, const char *range); // Type rules bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def, const char *obj); + const char *cls, const char *def, const char *obj); bool ksu_type_change(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def); + const char *cls, const char *def); bool ksu_type_member(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def); + const char *cls, const char *def); // File system labeling bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path, - const char *ctx); + const char *ctx); #endif diff --git a/kernel/setuid_hook.c b/kernel/setuid_hook.c index a4f3f9aa..e7867ec8 100644 --- a/kernel/setuid_hook.c +++ b/kernel/setuid_hook.c @@ -50,20 +50,20 @@ #ifdef CONFIG_KSU_SUSFS static inline bool is_some_system_uid(uid_t uid) { - uid %= 100000; - return (uid >= 1000 && uid < 10000); + uid %= 100000; + return (uid >= 1000 && uid < 10000); } static inline bool is_zygote_isolated_service_uid(uid_t uid) { - uid %= 100000; - return (uid >= 90000 && uid < 100000); + uid %= 100000; + return (uid >= 90000 && uid < 100000); } static inline bool is_zygote_normal_app_uid(uid_t uid) { - uid %= 100000; - return (uid >= 10000 && uid < 19999); + uid %= 100000; + return (uid >= 10000 && uid < 19999); } bool susfs_is_umount_for_zygote_system_process_enabled = false; @@ -148,7 +148,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) // disallow appuid decrease to any other uid if it is not allowed to su if (is_appuid(old_uid)) { if (euid < current_euid().val && - !ksu_is_allow_uid_for_current(old_uid)) { + !ksu_is_allow_uid_for_current(old_uid)) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); @@ -161,7 +161,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) // if on private space, see if its possibly the manager if (new_uid > PER_USER_RANGE && - new_uid % PER_USER_RANGE == ksu_get_manager_uid()) { + new_uid % PER_USER_RANGE == ksu_get_manager_uid()) { ksu_set_manager_uid(new_uid); } @@ -178,7 +178,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) if (ksu_is_allow_uid_for_current(new_uid)) { if (current->seccomp.mode == SECCOMP_MODE_FILTER && - current->seccomp.filter) { + current->seccomp.filter) { spin_lock_irq(¤t->sighand->siglock); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); @@ -213,53 +213,53 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) extern bool ksu_kernel_umount_enabled; extern bool ksu_module_mounted; int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ - // we rely on the fact that zygote always call setresuid(3) with same uids - uid_t new_uid = ruid; - uid_t old_uid = current_uid().val; + // we rely on the fact that zygote always call setresuid(3) with same uids + uid_t new_uid = ruid; + uid_t old_uid = current_uid().val; - // if old process is root, ignore it. - if (old_uid != 0 && ksu_enhanced_security_enabled) { - // disallow any non-ksu domain escalation from non-root to root! - // euid is what we care about here as it controls permission - if (unlikely(euid == 0)) { - if (!is_ksu_domain()) { - pr_warn("find suspicious EoP: %d %s, from %d to %d\n", - current->pid, current->comm, old_uid, new_uid); - __force_sig(SIGKILL); - return 0; - } - } - // disallow appuid decrease to any other uid if it is not allowed to su - if (is_appuid(old_uid)) { - if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) { - pr_warn("find suspicious EoP: %d %s, from %d to %d\n", - current->pid, current->comm, old_uid, new_uid); - __force_sig(SIGKILL); - return 0; - } - } - return 0; - } + // if old process is root, ignore it. + if (old_uid != 0 && ksu_enhanced_security_enabled) { + // disallow any non-ksu domain escalation from non-root to root! + // euid is what we care about here as it controls permission + if (unlikely(euid == 0)) { + if (!is_ksu_domain()) { + pr_warn("find suspicious EoP: %d %s, from %d to %d\n", + current->pid, current->comm, old_uid, new_uid); + __force_sig(SIGKILL); + return 0; + } + } + // disallow appuid decrease to any other uid if it is not allowed to su + if (is_appuid(old_uid)) { + if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) { + pr_warn("find suspicious EoP: %d %s, from %d to %d\n", + current->pid, current->comm, old_uid, new_uid); + __force_sig(SIGKILL); + return 0; + } + } + return 0; + } - // We only interest in process spwaned by zygote - if (!susfs_is_sid_equal(current_cred()->security, susfs_zygote_sid)) { - return 0; - } + // We only interest in process spwaned by zygote + if (!susfs_is_sid_equal(current_cred()->security, susfs_zygote_sid)) { + return 0; + } #if __SULOG_GATE - ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); + ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); #endif #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // Check if spawned process is isolated service first, and force to do umount if so - if (is_zygote_isolated_service_uid(new_uid) && susfs_is_umount_for_zygote_iso_service_enabled) { - goto do_umount; - } + // Check if spawned process is isolated service first, and force to do umount if so + if (is_zygote_isolated_service_uid(new_uid) && susfs_is_umount_for_zygote_iso_service_enabled) { + goto do_umount; + } #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // - Since ksu maanger app uid is excluded in allow_list_arr, so ksu_uid_should_umount(manager_uid) - // will always return true, that's why we need to explicitly check if new_uid belongs to - // ksu manager + // - Since ksu maanger app uid is excluded in allow_list_arr, so ksu_uid_should_umount(manager_uid) + // will always return true, that's why we need to explicitly check if new_uid belongs to + // ksu manager #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) if (ksu_get_manager_uid() == new_uid) { pr_info("install fd for ksu manager(uid=%d)\n", new_uid); @@ -272,7 +272,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ if (ksu_is_allow_uid_for_current(new_uid)) { if (current->seccomp.mode == SECCOMP_MODE_FILTER && - current->seccomp.filter) { + current->seccomp.filter) { spin_lock_irq(¤t->sighand->siglock); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); @@ -297,48 +297,48 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ } #endif - // Check if spawned process is normal user app and needs to be umounted - if (likely(is_zygote_normal_app_uid(new_uid) && ksu_uid_should_umount(new_uid))) { - goto do_umount; - } + // Check if spawned process is normal user app and needs to be umounted + if (likely(is_zygote_normal_app_uid(new_uid) && ksu_uid_should_umount(new_uid))) { + goto do_umount; + } - // Lastly, Check if spawned process is some system process and needs to be umounted - if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) { - goto do_umount; - } + // Lastly, Check if spawned process is some system process and needs to be umounted + if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) { + goto do_umount; + } - return 0; + return 0; do_umount: - if (!ksu_kernel_umount_enabled || !ksu_module_mounted) { - goto skip_try_umount; - - } + if (!ksu_kernel_umount_enabled || !ksu_module_mounted) { + goto skip_try_umount; + + } #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT - pr_info("susfs: running susfs_try_umount_all() for uid: %u\n", new_uid); - susfs_try_umount_all(); + pr_info("susfs: running susfs_try_umount_all() for uid: %u\n", new_uid); + susfs_try_umount_all(); #else - // Handle kernel umount - ksu_handle_umount(old_uid, new_uid); + // Handle kernel umount + ksu_handle_umount(old_uid, new_uid); #endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT skip_try_umount: - get_task_struct(current); + get_task_struct(current); #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // We can reorder the mnt_id now after all sus mounts are umounted - susfs_reorder_mnt_id(); + // We can reorder the mnt_id now after all sus mounts are umounted + susfs_reorder_mnt_id(); #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - susfs_set_current_proc_umounted(); + susfs_set_current_proc_umounted(); - put_task_struct(current); + put_task_struct(current); #ifdef CONFIG_KSU_SUSFS_SUS_PATH - susfs_run_sus_path_loop(new_uid); + susfs_run_sus_path_loop(new_uid); #endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH - return 0; + return 0; } #endif // #ifndef CONFIG_KSU_SUSFS diff --git a/kernel/setup.sh b/kernel/setup.sh index d013bfe2..62d1f807 100644 --- a/kernel/setup.sh +++ b/kernel/setup.sh @@ -4,77 +4,77 @@ set -eu GKI_ROOT=$(pwd) display_usage() { - echo "Usage: $0 [--cleanup | ]" - echo " --cleanup: Cleans up previous modifications made by the script." - echo " : Sets up or updates the KernelSU to specified tag or commit." - echo " -h, --help: Displays this usage information." - echo " (no args): Sets up or updates the KernelSU environment to the latest tagged version." + echo "Usage: $0 [--cleanup | ]" + echo " --cleanup: Cleans up previous modifications made by the script." + echo " : Sets up or updates the KernelSU to specified tag or commit." + echo " -h, --help: Displays this usage information." + echo " (no args): Sets up or updates the KernelSU environment to the latest tagged version." } initialize_variables() { - if test -d "$GKI_ROOT/common/drivers"; then - DRIVER_DIR="$GKI_ROOT/common/drivers" - elif test -d "$GKI_ROOT/drivers"; then - DRIVER_DIR="$GKI_ROOT/drivers" - else - echo '[ERROR] "drivers/" directory not found.' - exit 127 - fi + if test -d "$GKI_ROOT/common/drivers"; then + DRIVER_DIR="$GKI_ROOT/common/drivers" + elif test -d "$GKI_ROOT/drivers"; then + DRIVER_DIR="$GKI_ROOT/drivers" + else + echo '[ERROR] "drivers/" directory not found.' + exit 127 + fi - DRIVER_MAKEFILE=$DRIVER_DIR/Makefile - DRIVER_KCONFIG=$DRIVER_DIR/Kconfig + DRIVER_MAKEFILE=$DRIVER_DIR/Makefile + DRIVER_KCONFIG=$DRIVER_DIR/Kconfig } # Reverts modifications made by this script perform_cleanup() { - echo "[+] Cleaning up..." - [ -L "$DRIVER_DIR/kernelsu" ] && rm "$DRIVER_DIR/kernelsu" && echo "[-] Symlink removed." - grep -q "kernelsu" "$DRIVER_MAKEFILE" && sed -i '/kernelsu/d' "$DRIVER_MAKEFILE" && echo "[-] Makefile reverted." - grep -q "drivers/kernelsu/Kconfig" "$DRIVER_KCONFIG" && sed -i '/drivers\/kernelsu\/Kconfig/d' "$DRIVER_KCONFIG" && echo "[-] Kconfig reverted." - if [ -d "$GKI_ROOT/KernelSU" ]; then - rm -rf "$GKI_ROOT/KernelSU" && echo "[-] KernelSU directory deleted." - fi + echo "[+] Cleaning up..." + [ -L "$DRIVER_DIR/kernelsu" ] && rm "$DRIVER_DIR/kernelsu" && echo "[-] Symlink removed." + grep -q "kernelsu" "$DRIVER_MAKEFILE" && sed -i '/kernelsu/d' "$DRIVER_MAKEFILE" && echo "[-] Makefile reverted." + grep -q "drivers/kernelsu/Kconfig" "$DRIVER_KCONFIG" && sed -i '/drivers\/kernelsu\/Kconfig/d' "$DRIVER_KCONFIG" && echo "[-] Kconfig reverted." + if [ -d "$GKI_ROOT/KernelSU" ]; then + rm -rf "$GKI_ROOT/KernelSU" && echo "[-] KernelSU directory deleted." + fi } # Sets up or update KernelSU environment setup_kernelsu() { - echo "[+] Setting up KernelSU..." - # Clone the repository and rename it to KernelSU - if [ ! -d "$GKI_ROOT/KernelSU" ]; then - git clone https://github.com/SukiSU-Ultra/SukiSU-Ultra SukiSU-Ultra - mv SukiSU-Ultra KernelSU - echo "[+] Repository cloned and renamed to KernelSU." - fi - cd "$GKI_ROOT/KernelSU" - git stash && echo "[-] Stashed current changes." - if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then - git checkout main && echo "[-] Switched to main branch." - fi - git pull && echo "[+] Repository updated." - if [ -z "${1-}" ]; then - git checkout "$(git describe --abbrev=0 --tags)" && echo "[-] Checked out latest tag." - else - git checkout "$1" && echo "[-] Checked out $1." || echo "[-] Checkout default branch" - fi - cd "$DRIVER_DIR" - ln -sf "$(realpath --relative-to="$DRIVER_DIR" "$GKI_ROOT/KernelSU/kernel")" "kernelsu" && echo "[+] Symlink created." + echo "[+] Setting up KernelSU..." + # Clone the repository and rename it to KernelSU + if [ ! -d "$GKI_ROOT/KernelSU" ]; then + git clone https://github.com/SukiSU-Ultra/SukiSU-Ultra SukiSU-Ultra + mv SukiSU-Ultra KernelSU + echo "[+] Repository cloned and renamed to KernelSU." + fi + cd "$GKI_ROOT/KernelSU" + git stash && echo "[-] Stashed current changes." + if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then + git checkout main && echo "[-] Switched to main branch." + fi + git pull && echo "[+] Repository updated." + if [ -z "${1-}" ]; then + git checkout "$(git describe --abbrev=0 --tags)" && echo "[-] Checked out latest tag." + else + git checkout "$1" && echo "[-] Checked out $1." || echo "[-] Checkout default branch" + fi + cd "$DRIVER_DIR" + ln -sf "$(realpath --relative-to="$DRIVER_DIR" "$GKI_ROOT/KernelSU/kernel")" "kernelsu" && echo "[+] Symlink created." - # Add entries in Makefile and Kconfig if not already existing - grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE" && echo "[+] Modified Makefile." - grep -q "source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG" && echo "[+] Modified Kconfig." - echo '[+] Done.' + # Add entries in Makefile and Kconfig if not already existing + grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE" && echo "[+] Modified Makefile." + grep -q "source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG" && echo "[+] Modified Kconfig." + echo '[+] Done.' } # Process command-line arguments if [ "$#" -eq 0 ]; then - initialize_variables - setup_kernelsu + initialize_variables + setup_kernelsu elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then - display_usage + display_usage elif [ "$1" = "--cleanup" ]; then - initialize_variables - perform_cleanup + initialize_variables + perform_cleanup else - initialize_variables - setup_kernelsu "$@" + initialize_variables + setup_kernelsu "$@" fi \ No newline at end of file diff --git a/kernel/sucompat.c b/kernel/sucompat.c index 696e2343..b59de40e 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -37,168 +37,168 @@ bool ksu_su_compat_enabled __read_mostly = true; static int su_compat_feature_get(u64 *value) { - *value = ksu_su_compat_enabled ? 1 : 0; - return 0; + *value = ksu_su_compat_enabled ? 1 : 0; + return 0; } static int su_compat_feature_set(u64 value) { - bool enable = value != 0; - ksu_su_compat_enabled = enable; - pr_info("su_compat: set to %d\n", enable); - return 0; + bool enable = value != 0; + ksu_su_compat_enabled = enable; + pr_info("su_compat: set to %d\n", enable); + return 0; } static const struct ksu_feature_handler su_compat_handler = { - .feature_id = KSU_FEATURE_SU_COMPAT, - .name = "su_compat", - .get_handler = su_compat_feature_get, - .set_handler = su_compat_feature_set, + .feature_id = KSU_FEATURE_SU_COMPAT, + .name = "su_compat", + .get_handler = su_compat_feature_get, + .set_handler = su_compat_feature_set, }; static void __user *userspace_stack_buffer(const void *d, size_t len) { - // To avoid having to mmap a page in userspace, just write below the stack - // pointer. - char __user *p = (void __user *)current_user_stack_pointer() - len; + // To avoid having to mmap a page in userspace, just write below the stack + // pointer. + char __user *p = (void __user *)current_user_stack_pointer() - len; - return copy_to_user(p, d, len) ? NULL : p; + return copy_to_user(p, d, len) ? NULL : p; } static char __user *sh_user_path(void) { - static const char sh_path[] = "/system/bin/sh"; + static const char sh_path[] = "/system/bin/sh"; - return userspace_stack_buffer(sh_path, sizeof(sh_path)); + return userspace_stack_buffer(sh_path, sizeof(sh_path)); } static char __user *ksud_user_path(void) { - static const char ksud_path[] = KSUD_PATH; + static const char ksud_path[] = KSUD_PATH; - return userspace_stack_buffer(ksud_path, sizeof(ksud_path)); + return userspace_stack_buffer(ksud_path, sizeof(ksud_path)); } #ifndef CONFIG_KSU_SUSFS int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *__unused_flags) + int *__unused_flags) { - const char su[] = SU_PATH; + const char su[] = SU_PATH; #ifdef KSU_MANUAL_HOOK - if (!ksu_su_compat_enabled) { - return 0; - } + if (!ksu_su_compat_enabled) { + return 0; + } #endif - if (!ksu_is_allow_uid_for_current(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid_for_current(current_uid().val)) { + return 0; + } - char path[sizeof(su) + 1]; - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + char path[sizeof(su) + 1]; + memset(path, 0, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (unlikely(!memcmp(path, su, sizeof(su)))) { + if (unlikely(!memcmp(path, su, sizeof(su)))) { #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "faccessat", path); + ksu_sulog_report_syscall(current_uid().val, NULL, "faccessat", path); #endif - pr_info("faccessat su->sh!\n"); - *filename_user = sh_user_path(); - } + pr_info("faccessat su->sh!\n"); + *filename_user = sh_user_path(); + } - return 0; + return 0; } int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) { - // const char sh[] = SH_PATH; - const char su[] = SU_PATH; + // const char sh[] = SH_PATH; + const char su[] = SU_PATH; #ifdef KSU_MANUAL_HOOK - if (!ksu_su_compat_enabled) { - return 0; - } + if (!ksu_su_compat_enabled) { + return 0; + } #endif - if (!ksu_is_allow_uid_for_current(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid_for_current(current_uid().val)) { + return 0; + } - if (unlikely(!filename_user)) { - return 0; - } + if (unlikely(!filename_user)) { + return 0; + } - char path[sizeof(su) + 1]; - memset(path, 0, sizeof(path)); + char path[sizeof(su) + 1]; + memset(path, 0, sizeof(path)); // Remove this later!! we use syscall hook, so this will never happen!!!!! #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0 - // it becomes a `struct filename *` after 5.18 - // https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216 - const char sh[] = SH_PATH; - struct filename *filename = *((struct filename **)filename_user); - if (IS_ERR(filename)) { - return 0; - } - if (likely(memcmp(filename->name, su, sizeof(su)))) - return 0; - pr_info("vfs_statx su->sh!\n"); - memcpy((void *)filename->name, sh, sizeof(sh)); + // it becomes a `struct filename *` after 5.18 + // https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216 + const char sh[] = SH_PATH; + struct filename *filename = *((struct filename **)filename_user); + if (IS_ERR(filename)) { + return 0; + } + if (likely(memcmp(filename->name, su, sizeof(su)))) + return 0; + pr_info("vfs_statx su->sh!\n"); + memcpy((void *)filename->name, sh, sizeof(sh)); #else - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (unlikely(!memcmp(path, su, sizeof(su)))) { + if (unlikely(!memcmp(path, su, sizeof(su)))) { #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "newfstatat", path); + ksu_sulog_report_syscall(current_uid().val, NULL, "newfstatat", path); #endif - pr_info("newfstatat su->sh!\n"); - *filename_user = sh_user_path(); - } + pr_info("newfstatat su->sh!\n"); + *filename_user = sh_user_path(); + } #endif - return 0; + return 0; } int ksu_handle_execve_sucompat(const char __user **filename_user, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags) + void *__never_use_argv, void *__never_use_envp, + int *__never_use_flags) { - const char su[] = SU_PATH; - char path[sizeof(su) + 1]; + const char su[] = SU_PATH; + char path[sizeof(su) + 1]; #ifdef KSU_MANUAL_HOOK - if (!ksu_su_compat_enabled){ - return 0; - } + if (!ksu_su_compat_enabled){ + return 0; + } #endif - if (unlikely(!filename_user)) - return 0; + if (unlikely(!filename_user)) + return 0; - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + memset(path, 0, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (likely(memcmp(path, su, sizeof(su)))) - return 0; + if (likely(memcmp(path, su, sizeof(su)))) + return 0; #if __SULOG_GATE - bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val); - ksu_sulog_report_syscall(current_uid().val, NULL, "execve", path); - - if (!is_allowed) - return 0; + bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val); + ksu_sulog_report_syscall(current_uid().val, NULL, "execve", path); + + if (!is_allowed) + return 0; - ksu_sulog_report_su_attempt(current_uid().val, NULL, path, is_allowed); + ksu_sulog_report_su_attempt(current_uid().val, NULL, path, is_allowed); #else - if (!ksu_is_allow_uid_for_current(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid_for_current(current_uid().val)) { + return 0; + } #endif - pr_info("sys_execve su found\n"); - *filename_user = ksud_user_path(); + pr_info("sys_execve su found\n"); + *filename_user = ksud_user_path(); - escape_with_root_profile(); + escape_with_root_profile(); - return 0; + return 0; } #else static const char sh_path[] = SH_PATH; @@ -207,169 +207,169 @@ static const char ksud_path[] = KSUD_PATH; // the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags) + void *__never_use_argv, void *__never_use_envp, + int *__never_use_flags) { - struct filename *filename; + struct filename *filename; - if (!ksu_su_compat_enabled){ - return 0; - } + if (!ksu_su_compat_enabled){ + return 0; + } - if (unlikely(!filename_ptr)) - return 0; + if (unlikely(!filename_ptr)) + return 0; - filename = *filename_ptr; - if (IS_ERR(filename)) { - return 0; - } + filename = *filename_ptr; + if (IS_ERR(filename)) { + return 0; + } - if (likely(memcmp(filename->name, su_path, sizeof(su_path)))) - return 0; + if (likely(memcmp(filename->name, su_path, sizeof(su_path)))) + return 0; #if __SULOG_GATE - bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val); - ksu_sulog_report_syscall(current_uid().val, NULL, "execve", su_path); - ksu_sulog_report_su_attempt(current_uid().val, NULL, su_path, is_allowed); + bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val); + ksu_sulog_report_syscall(current_uid().val, NULL, "execve", su_path); + ksu_sulog_report_su_attempt(current_uid().val, NULL, su_path, is_allowed); #endif - pr_info("do_execveat_common su found\n"); - memcpy((void *)filename->name, ksud_path, sizeof(ksud_path)); + pr_info("do_execveat_common su found\n"); + memcpy((void *)filename->name, ksud_path, sizeof(ksud_path)); - escape_with_root_profile(); + escape_with_root_profile(); - return 0; + return 0; } int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags) + void *envp, int *flags) { - if (ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags)) { - return 0; - } - return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, - flags); + if (ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags)) { + return 0; + } + return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, + flags); } int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *__unused_flags) + int *__unused_flags) { - char path[sizeof(su_path) + 1] = {0}; + char path[sizeof(su_path) + 1] = {0}; - if (!ksu_su_compat_enabled){ - return 0; - } + if (!ksu_su_compat_enabled){ + return 0; + } - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (unlikely(!memcmp(path, su_path, sizeof(su_path)))) { + if (unlikely(!memcmp(path, su_path, sizeof(su_path)))) { #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "faccessat", path); + ksu_sulog_report_syscall(current_uid().val, NULL, "faccessat", path); #endif - pr_info("faccessat su->sh!\n"); - *filename_user = sh_user_path(); - } + pr_info("faccessat su->sh!\n"); + *filename_user = sh_user_path(); + } - return 0; + return 0; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) int ksu_handle_stat(int *dfd, struct filename **filename, int *flags) { - if (unlikely(IS_ERR(*filename) || (*filename)->name == NULL)) { - return 0; - } + if (unlikely(IS_ERR(*filename) || (*filename)->name == NULL)) { + return 0; + } - if (likely(memcmp((*filename)->name, su_path, sizeof(su_path)))) { - return 0; - } + if (likely(memcmp((*filename)->name, su_path, sizeof(su_path)))) { + return 0; + } - pr_info("ksu_handle_stat: su->sh!\n"); - memcpy((void *)((*filename)->name), sh_path, sizeof(sh_path)); - return 0; + pr_info("ksu_handle_stat: su->sh!\n"); + memcpy((void *)((*filename)->name), sh_path, sizeof(sh_path)); + return 0; } #else int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) { - if (!ksu_su_compat_enabled){ - return 0; - } + if (!ksu_su_compat_enabled){ + return 0; + } - if (unlikely(!filename_user)) { - return 0; - } + if (unlikely(!filename_user)) { + return 0; + } - char path[sizeof(su_path) + 1] = {0}; + char path[sizeof(su_path) + 1] = {0}; // Remove this later!! we use syscall hook, so this will never happen!!!!! #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0 - // it becomes a `struct filename *` after 5.18 - // https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216 + // it becomes a `struct filename *` after 5.18 + // https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216 #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) - struct filename *filename = *((struct filename **)filename_user); + struct filename *filename = *((struct filename **)filename_user); #endif - if (IS_ERR(filename)) { - return 0; - } - if (likely(memcmp(filename->name, su_path, sizeof(su_path)))) - return 0; - pr_info("ksu_handle_stat: su->sh!\n"); - memcpy((void *)filename->name, sh_path, sizeof(sh_path)); + if (IS_ERR(filename)) { + return 0; + } + if (likely(memcmp(filename->name, su_path, sizeof(su_path)))) + return 0; + pr_info("ksu_handle_stat: su->sh!\n"); + memcpy((void *)filename->name, sh_path, sizeof(sh_path)); #else - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (unlikely(!memcmp(path, su_path, sizeof(su_path)))) { + if (unlikely(!memcmp(path, su_path, sizeof(su_path)))) { #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "newfstatat", path); + ksu_sulog_report_syscall(current_uid().val, NULL, "newfstatat", path); #endif - pr_info("ksu_handle_stat: su->sh!\n"); - *filename_user = sh_user_path(); - } + pr_info("ksu_handle_stat: su->sh!\n"); + *filename_user = sh_user_path(); + } #endif - return 0; + return 0; } #endif // #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) int ksu_handle_devpts(struct inode *inode) { - if (!current->mm) { - return 0; - } + if (!current->mm) { + return 0; + } - if (!ksu_su_compat_enabled){ - return 0; - } + if (!ksu_su_compat_enabled){ + return 0; + } - uid_t uid = current_uid().val; - if (uid % 100000 < 10000) { - // not untrusted_app, ignore it - return 0; - } + uid_t uid = current_uid().val; + if (uid % 100000 < 10000) { + // not untrusted_app, ignore it + return 0; + } - if (!__ksu_is_allow_uid_for_current(uid)) - return 0; + if (!__ksu_is_allow_uid_for_current(uid)) + return 0; - if (ksu_file_sid) { - struct inode_security_struct *sec = selinux_inode(inode); - if (sec) { - sec->sid = ksu_file_sid; - } - } + if (ksu_file_sid) { + struct inode_security_struct *sec = selinux_inode(inode); + if (sec) { + sec->sid = ksu_file_sid; + } + } - return 0; + return 0; } #endif // #ifndef CONFIG_KSU_SUSFS // sucompat: permitted process can execute 'su' to gain root access. void ksu_sucompat_init() { - if (ksu_register_feature_handler(&su_compat_handler)) { - pr_err("Failed to register su_compat feature handler\n"); - } + if (ksu_register_feature_handler(&su_compat_handler)) { + pr_err("Failed to register su_compat feature handler\n"); + } } void ksu_sucompat_exit() { - ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT); + ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT); } diff --git a/kernel/sucompat.h b/kernel/sucompat.h index 7f66e3ea..6eba887c 100644 --- a/kernel/sucompat.h +++ b/kernel/sucompat.h @@ -16,7 +16,7 @@ int ksu_handle_stat(int *dfd, struct filename **filename, int *flags); int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); #endif // #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS) int ksu_handle_execve_sucompat(const char __user **filename_user, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags); + void *__never_use_argv, void *__never_use_envp, + int *__never_use_flags); #endif \ No newline at end of file diff --git a/kernel/sulog.c b/kernel/sulog.c index 21e11c39..4e4cf9d9 100644 --- a/kernel/sulog.c +++ b/kernel/sulog.c @@ -30,340 +30,340 @@ static bool sulog_enabled __read_mostly = true; static int sulog_feature_get(u64 *value) { - *value = sulog_enabled ? 1 : 0; - return 0; + *value = sulog_enabled ? 1 : 0; + return 0; } static int sulog_feature_set(u64 value) { - bool enable = value != 0; - sulog_enabled = enable; - pr_info("sulog: set to %d\n", enable); - return 0; + bool enable = value != 0; + sulog_enabled = enable; + pr_info("sulog: set to %d\n", enable); + return 0; } static const struct ksu_feature_handler sulog_handler = { - .feature_id = KSU_FEATURE_SULOG, - .name = "sulog", - .get_handler = sulog_feature_get, - .set_handler = sulog_feature_set, + .feature_id = KSU_FEATURE_SULOG, + .name = "sulog", + .get_handler = sulog_feature_get, + .set_handler = sulog_feature_set, }; static void get_timestamp(char *buf, size_t len) { - struct timespec64 ts; - struct tm tm; + struct timespec64 ts; + struct tm tm; - ktime_get_real_ts64(&ts); - time64_to_tm(ts.tv_sec - sys_tz.tz_minuteswest * 60, 0, &tm); + ktime_get_real_ts64(&ts); + time64_to_tm(ts.tv_sec - sys_tz.tz_minuteswest * 60, 0, &tm); - snprintf(buf, len, "%04ld-%02d-%02d %02d:%02d:%02d", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + snprintf(buf, len, "%04ld-%02d-%02d %02d:%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); } static void ksu_get_cmdline(char *full_comm, const char *comm, size_t buf_len) { - if (!full_comm || buf_len <= 0) - return; + if (!full_comm || buf_len <= 0) + return; - if (comm && strlen(comm) > 0) { - KSU_STRSCPY(full_comm, comm, buf_len); - return; - } + if (comm && strlen(comm) > 0) { + KSU_STRSCPY(full_comm, comm, buf_len); + return; + } - if (in_atomic() || in_interrupt() || irqs_disabled()) { - KSU_STRSCPY(full_comm, current->comm, buf_len); - return; - } + if (in_atomic() || in_interrupt() || irqs_disabled()) { + KSU_STRSCPY(full_comm, current->comm, buf_len); + return; + } - if (!current->mm) { - KSU_STRSCPY(full_comm, current->comm, buf_len); - return; - } + if (!current->mm) { + KSU_STRSCPY(full_comm, current->comm, buf_len); + return; + } - int n = get_cmdline(current, full_comm, buf_len); - if (n <= 0) { - KSU_STRSCPY(full_comm, current->comm, buf_len); - return; - } + int n = get_cmdline(current, full_comm, buf_len); + if (n <= 0) { + KSU_STRSCPY(full_comm, current->comm, buf_len); + return; + } - for (int i = 0; i < n && i < buf_len - 1; i++) { - if (full_comm[i] == '\0') - full_comm[i] = ' '; - } - full_comm[n < buf_len ? n : buf_len - 1] = '\0'; + for (int i = 0; i < n && i < buf_len - 1; i++) { + if (full_comm[i] == '\0') + full_comm[i] = ' '; + } + full_comm[n < buf_len ? n : buf_len - 1] = '\0'; } static void sanitize_string(char *str, size_t len) { - if (!str || len == 0) - return; - - size_t read_pos = 0, write_pos = 0; - - while (read_pos < len && str[read_pos] != '\0') { - char c = str[read_pos]; - - if (c == '\n' || c == '\r') { - read_pos++; - continue; - } - - if (c == ' ' && write_pos > 0 && str[write_pos - 1] == ' ') { - read_pos++; - continue; - } - - str[write_pos++] = c; - read_pos++; - } - - str[write_pos] = '\0'; + if (!str || len == 0) + return; + + size_t read_pos = 0, write_pos = 0; + + while (read_pos < len && str[read_pos] != '\0') { + char c = str[read_pos]; + + if (c == '\n' || c == '\r') { + read_pos++; + continue; + } + + if (c == ' ' && write_pos > 0 && str[write_pos - 1] == ' ') { + read_pos++; + continue; + } + + str[write_pos++] = c; + read_pos++; + } + + str[write_pos] = '\0'; } static bool dedup_should_print(uid_t uid, u8 type, const char *content, size_t len) { - struct dedup_key key = { - .crc = dedup_calc_hash(content, len), - .uid = uid, - .type = type, - }; - u64 now = ktime_get_ns(); - u64 delta_ns = DEDUP_SECS * NSEC_PER_SEC; + struct dedup_key key = { + .crc = dedup_calc_hash(content, len), + .uid = uid, + .type = type, + }; + u64 now = ktime_get_ns(); + u64 delta_ns = DEDUP_SECS * NSEC_PER_SEC; - u32 idx = key.crc & (SULOG_COMM_LEN - 1); - spin_lock(&dedup_lock); + u32 idx = key.crc & (SULOG_COMM_LEN - 1); + spin_lock(&dedup_lock); - struct dedup_entry *e = &dedup_tbl[idx]; - if (e->key.crc == key.crc && - e->key.uid == key.uid && - e->key.type == key.type && - (now - e->ts_ns) < delta_ns) { - spin_unlock(&dedup_lock); - return false; - } + struct dedup_entry *e = &dedup_tbl[idx]; + if (e->key.crc == key.crc && + e->key.uid == key.uid && + e->key.type == key.type && + (now - e->ts_ns) < delta_ns) { + spin_unlock(&dedup_lock); + return false; + } - e->key = key; - e->ts_ns = now; - spin_unlock(&dedup_lock); - return true; + e->key = key; + e->ts_ns = now; + spin_unlock(&dedup_lock); + return true; } static void sulog_work_handler(struct work_struct *work) { - struct file *fp; - struct sulog_entry *entry, *tmp; - LIST_HEAD(local_queue); - loff_t pos = 0; - unsigned long flags; + struct file *fp; + struct sulog_entry *entry, *tmp; + LIST_HEAD(local_queue); + loff_t pos = 0; + unsigned long flags; - spin_lock_irqsave(&dedup_lock, flags); - list_splice_init(&sulog_queue, &local_queue); - spin_unlock_irqrestore(&dedup_lock, flags); + spin_lock_irqsave(&dedup_lock, flags); + list_splice_init(&sulog_queue, &local_queue); + spin_unlock_irqrestore(&dedup_lock, flags); - if (list_empty(&local_queue)) - return; + if (list_empty(&local_queue)) + return; - fp = ksu_filp_open_compat(SULOG_PATH, O_WRONLY | O_CREAT | O_APPEND, 0640); - if (IS_ERR(fp)) { - pr_err("sulog: failed to open log file: %ld\n", PTR_ERR(fp)); - goto cleanup; - } + fp = ksu_filp_open_compat(SULOG_PATH, O_WRONLY | O_CREAT | O_APPEND, 0640); + if (IS_ERR(fp)) { + pr_err("sulog: failed to open log file: %ld\n", PTR_ERR(fp)); + goto cleanup; + } - if (fp->f_inode->i_size > SULOG_MAX_SIZE) { - if (vfs_truncate(&fp->f_path, 0)) - pr_err("sulog: failed to truncate log file\n"); - pos = 0; - } else { - pos = fp->f_inode->i_size; - } + if (fp->f_inode->i_size > SULOG_MAX_SIZE) { + if (vfs_truncate(&fp->f_path, 0)) + pr_err("sulog: failed to truncate log file\n"); + pos = 0; + } else { + pos = fp->f_inode->i_size; + } - list_for_each_entry(entry, &local_queue, list) - ksu_kernel_write_compat(fp, entry->content, strlen(entry->content), &pos); + list_for_each_entry(entry, &local_queue, list) + ksu_kernel_write_compat(fp, entry->content, strlen(entry->content), &pos); - vfs_fsync(fp, 0); - filp_close(fp, 0); + vfs_fsync(fp, 0); + filp_close(fp, 0); cleanup: - list_for_each_entry_safe(entry, tmp, &local_queue, list) { - list_del(&entry->list); - kfree(entry); - } + list_for_each_entry_safe(entry, tmp, &local_queue, list) { + list_del(&entry->list); + kfree(entry); + } } static void sulog_add_entry(char *log_buf, size_t len, uid_t uid, u8 dedup_type) { - struct sulog_entry *entry; - unsigned long flags; + struct sulog_entry *entry; + unsigned long flags; - if (!sulog_enabled || !log_buf || len == 0) - return; + if (!sulog_enabled || !log_buf || len == 0) + return; - if (!dedup_should_print(uid, dedup_type, log_buf, len)) - return; + if (!dedup_should_print(uid, dedup_type, log_buf, len)) + return; - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) - return; + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) + return; - KSU_STRSCPY(entry->content, log_buf, SULOG_ENTRY_MAX_LEN); + KSU_STRSCPY(entry->content, log_buf, SULOG_ENTRY_MAX_LEN); - spin_lock_irqsave(&dedup_lock, flags); - list_add_tail(&entry->list, &sulog_queue); - spin_unlock_irqrestore(&dedup_lock, flags); + spin_lock_irqsave(&dedup_lock, flags); + list_add_tail(&entry->list, &sulog_queue); + spin_unlock_irqrestore(&dedup_lock, flags); - if (sulog_workqueue) - queue_work(sulog_workqueue, &sulog_work); + if (sulog_workqueue) + queue_work(sulog_workqueue, &sulog_work); } void ksu_sulog_report_su_grant(uid_t uid, const char *comm, const char *method) { - char log_buf[SULOG_ENTRY_MAX_LEN]; - char timestamp[32]; - char full_comm[SULOG_COMM_LEN]; + char log_buf[SULOG_ENTRY_MAX_LEN]; + char timestamp[32]; + char full_comm[SULOG_COMM_LEN]; - if (!sulog_enabled) - return; + if (!sulog_enabled) + return; - get_timestamp(timestamp, sizeof(timestamp)); - ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); - - sanitize_string(full_comm, sizeof(full_comm)); + get_timestamp(timestamp, sizeof(timestamp)); + ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); + + sanitize_string(full_comm, sizeof(full_comm)); - snprintf(log_buf, sizeof(log_buf), - "[%s] SU_GRANT: UID=%d COMM=%s METHOD=%s PID=%d\n", - timestamp, uid, full_comm, method ? method : "unknown", current->pid); + snprintf(log_buf, sizeof(log_buf), + "[%s] SU_GRANT: UID=%d COMM=%s METHOD=%s PID=%d\n", + timestamp, uid, full_comm, method ? method : "unknown", current->pid); - sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SU_GRANT); + sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SU_GRANT); } void ksu_sulog_report_su_attempt(uid_t uid, const char *comm, const char *target_path, bool success) { - char log_buf[SULOG_ENTRY_MAX_LEN]; - char timestamp[32]; - char full_comm[SULOG_COMM_LEN]; + char log_buf[SULOG_ENTRY_MAX_LEN]; + char timestamp[32]; + char full_comm[SULOG_COMM_LEN]; - if (!sulog_enabled) - return; + if (!sulog_enabled) + return; - get_timestamp(timestamp, sizeof(timestamp)); - ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); - - sanitize_string(full_comm, sizeof(full_comm)); + get_timestamp(timestamp, sizeof(timestamp)); + ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); + + sanitize_string(full_comm, sizeof(full_comm)); - snprintf(log_buf, sizeof(log_buf), - "[%s] SU_EXEC: UID=%d COMM=%s TARGET=%s RESULT=%s PID=%d\n", - timestamp, uid, full_comm, target_path ? target_path : "unknown", - success ? "SUCCESS" : "DENIED", current->pid); + snprintf(log_buf, sizeof(log_buf), + "[%s] SU_EXEC: UID=%d COMM=%s TARGET=%s RESULT=%s PID=%d\n", + timestamp, uid, full_comm, target_path ? target_path : "unknown", + success ? "SUCCESS" : "DENIED", current->pid); - sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SU_ATTEMPT); + sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SU_ATTEMPT); } void ksu_sulog_report_permission_check(uid_t uid, const char *comm, bool allowed) { - char log_buf[SULOG_ENTRY_MAX_LEN]; - char timestamp[32]; - char full_comm[SULOG_COMM_LEN]; + char log_buf[SULOG_ENTRY_MAX_LEN]; + char timestamp[32]; + char full_comm[SULOG_COMM_LEN]; - if (!sulog_enabled) - return; + if (!sulog_enabled) + return; - get_timestamp(timestamp, sizeof(timestamp)); - ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); - - sanitize_string(full_comm, sizeof(full_comm)); + get_timestamp(timestamp, sizeof(timestamp)); + ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); + + sanitize_string(full_comm, sizeof(full_comm)); - snprintf(log_buf, sizeof(log_buf), - "[%s] PERM_CHECK: UID=%d COMM=%s RESULT=%s PID=%d\n", - timestamp, uid, full_comm, allowed ? "ALLOWED" : "DENIED", current->pid); + snprintf(log_buf, sizeof(log_buf), + "[%s] PERM_CHECK: UID=%d COMM=%s RESULT=%s PID=%d\n", + timestamp, uid, full_comm, allowed ? "ALLOWED" : "DENIED", current->pid); - sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_PERM_CHECK); + sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_PERM_CHECK); } void ksu_sulog_report_manager_operation(const char *operation, uid_t manager_uid, uid_t target_uid) { - char log_buf[SULOG_ENTRY_MAX_LEN]; - char timestamp[32]; - char full_comm[SULOG_COMM_LEN]; + char log_buf[SULOG_ENTRY_MAX_LEN]; + char timestamp[32]; + char full_comm[SULOG_COMM_LEN]; - if (!sulog_enabled) - return; + if (!sulog_enabled) + return; - get_timestamp(timestamp, sizeof(timestamp)); - ksu_get_cmdline(full_comm, NULL, sizeof(full_comm)); - - sanitize_string(full_comm, sizeof(full_comm)); + get_timestamp(timestamp, sizeof(timestamp)); + ksu_get_cmdline(full_comm, NULL, sizeof(full_comm)); + + sanitize_string(full_comm, sizeof(full_comm)); - snprintf(log_buf, sizeof(log_buf), - "[%s] MANAGER_OP: OP=%s MANAGER_UID=%d TARGET_UID=%d COMM=%s PID=%d\n", - timestamp, operation ? operation : "unknown", manager_uid, target_uid, full_comm, current->pid); + snprintf(log_buf, sizeof(log_buf), + "[%s] MANAGER_OP: OP=%s MANAGER_UID=%d TARGET_UID=%d COMM=%s PID=%d\n", + timestamp, operation ? operation : "unknown", manager_uid, target_uid, full_comm, current->pid); - sulog_add_entry(log_buf, strlen(log_buf), manager_uid, DEDUP_MANAGER_OP); + sulog_add_entry(log_buf, strlen(log_buf), manager_uid, DEDUP_MANAGER_OP); } void ksu_sulog_report_syscall(uid_t uid, const char *comm, const char *syscall, const char *args) { - char log_buf[SULOG_ENTRY_MAX_LEN]; - char timestamp[32]; - char full_comm[SULOG_COMM_LEN]; + char log_buf[SULOG_ENTRY_MAX_LEN]; + char timestamp[32]; + char full_comm[SULOG_COMM_LEN]; - if (!sulog_enabled) - return; + if (!sulog_enabled) + return; - get_timestamp(timestamp, sizeof(timestamp)); - ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); - - sanitize_string(full_comm, sizeof(full_comm)); + get_timestamp(timestamp, sizeof(timestamp)); + ksu_get_cmdline(full_comm, comm, sizeof(full_comm)); + + sanitize_string(full_comm, sizeof(full_comm)); - snprintf(log_buf, sizeof(log_buf), - "[%s] SYSCALL: UID=%d COMM=%s SYSCALL=%s ARGS=%s PID=%d\n", - timestamp, uid, full_comm, syscall ? syscall : "unknown", - args ? args : "none", current->pid); + snprintf(log_buf, sizeof(log_buf), + "[%s] SYSCALL: UID=%d COMM=%s SYSCALL=%s ARGS=%s PID=%d\n", + timestamp, uid, full_comm, syscall ? syscall : "unknown", + args ? args : "none", current->pid); - sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SYSCALL); + sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SYSCALL); } int ksu_sulog_init(void) { - if (ksu_register_feature_handler(&sulog_handler)) { - pr_err("Failed to register sulog feature handler\n"); - } + if (ksu_register_feature_handler(&sulog_handler)) { + pr_err("Failed to register sulog feature handler\n"); + } - sulog_workqueue = alloc_workqueue("ksu_sulog", WQ_UNBOUND | WQ_HIGHPRI, 1); - if (!sulog_workqueue) { - pr_err("sulog: failed to create workqueue\n"); - return -ENOMEM; - } + sulog_workqueue = alloc_workqueue("ksu_sulog", WQ_UNBOUND | WQ_HIGHPRI, 1); + if (!sulog_workqueue) { + pr_err("sulog: failed to create workqueue\n"); + return -ENOMEM; + } - INIT_WORK(&sulog_work, sulog_work_handler); - pr_info("sulog: initialized successfully\n"); - return 0; + INIT_WORK(&sulog_work, sulog_work_handler); + pr_info("sulog: initialized successfully\n"); + return 0; } void ksu_sulog_exit(void) { - struct sulog_entry *entry, *tmp; - unsigned long flags; + struct sulog_entry *entry, *tmp; + unsigned long flags; - ksu_unregister_feature_handler(KSU_FEATURE_SULOG); + ksu_unregister_feature_handler(KSU_FEATURE_SULOG); - sulog_enabled = false; + sulog_enabled = false; - if (sulog_workqueue) { - flush_workqueue(sulog_workqueue); - destroy_workqueue(sulog_workqueue); - sulog_workqueue = NULL; - } + if (sulog_workqueue) { + flush_workqueue(sulog_workqueue); + destroy_workqueue(sulog_workqueue); + sulog_workqueue = NULL; + } - spin_lock_irqsave(&dedup_lock, flags); - list_for_each_entry_safe(entry, tmp, &sulog_queue, list) { - list_del(&entry->list); - kfree(entry); - } - spin_unlock_irqrestore(&dedup_lock, flags); + spin_lock_irqsave(&dedup_lock, flags); + list_for_each_entry_safe(entry, tmp, &sulog_queue, list) { + list_del(&entry->list); + kfree(entry); + } + spin_unlock_irqrestore(&dedup_lock, flags); - pr_info("sulog: cleaned up successfully\n"); + pr_info("sulog: cleaned up successfully\n"); } #endif // __SULOG_GATE diff --git a/kernel/sulog.h b/kernel/sulog.h index b1243554..7031b5b0 100644 --- a/kernel/sulog.h +++ b/kernel/sulog.h @@ -5,7 +5,7 @@ #include #include // needed for function dedup_calc_hash -#define __SULOG_GATE 1 +#define __SULOG_GATE 1 #if __SULOG_GATE @@ -20,64 +20,64 @@ extern struct timezone sys_tz; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) static inline size_t strlcpy(char *dest, const char *src, size_t size) { - return strscpy(dest, src, size); + return strscpy(dest, src, size); } #endif #define KSU_STRSCPY(dst, src, size) \ - do { \ - if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) { \ - strscpy(dst, src, size); \ - } else { \ - strlcpy(dst, src, size); \ - } \ - } while (0) + do { \ + if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) { \ + strscpy(dst, src, size); \ + } else { \ + strlcpy(dst, src, size); \ + } \ + } while (0) #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) #include static inline void time64_to_tm(time64_t totalsecs, int offset, struct tm *result) { - struct rtc_time rtc_tm; - rtc_time64_to_tm(totalsecs, &rtc_tm); + struct rtc_time rtc_tm; + rtc_time64_to_tm(totalsecs, &rtc_tm); - result->tm_sec = rtc_tm.tm_sec; - result->tm_min = rtc_tm.tm_min; - result->tm_hour = rtc_tm.tm_hour; - result->tm_mday = rtc_tm.tm_mday; - result->tm_mon = rtc_tm.tm_mon; - result->tm_year = rtc_tm.tm_year; + result->tm_sec = rtc_tm.tm_sec; + result->tm_min = rtc_tm.tm_min; + result->tm_hour = rtc_tm.tm_hour; + result->tm_mday = rtc_tm.tm_mday; + result->tm_mon = rtc_tm.tm_mon; + result->tm_year = rtc_tm.tm_year; } #endif struct dedup_key { - u32 crc; - uid_t uid; - u8 type; - u8 _pad[1]; + u32 crc; + uid_t uid; + u8 type; + u8 _pad[1]; }; struct dedup_entry { - struct dedup_key key; - u64 ts_ns; + struct dedup_key key; + u64 ts_ns; }; enum { - DEDUP_SU_GRANT = 0, - DEDUP_SU_ATTEMPT, - DEDUP_PERM_CHECK, - DEDUP_MANAGER_OP, - DEDUP_SYSCALL, + DEDUP_SU_GRANT = 0, + DEDUP_SU_ATTEMPT, + DEDUP_PERM_CHECK, + DEDUP_MANAGER_OP, + DEDUP_SYSCALL, }; static inline u32 dedup_calc_hash(const char *content, size_t len) { - return crc32(0, content, len); + return crc32(0, content, len); } struct sulog_entry { - struct list_head list; - char content[SULOG_ENTRY_MAX_LEN]; + struct list_head list; + char content[SULOG_ENTRY_MAX_LEN]; }; void ksu_sulog_report_su_grant(uid_t uid, const char *comm, const char *method); diff --git a/kernel/supercalls.c b/kernel/supercalls.c index 303fd897..985e6ae8 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -53,34 +53,34 @@ extern bool susfs_is_auto_add_try_umount_for_bind_mount_enabled; #endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT static void susfs_on_post_fs_data(void) { - struct path path; + struct path path; #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (!kern_path(DATA_ADB_UMOUNT_FOR_ZYGOTE_SYSTEM_PROCESS, 0, &path)) { - susfs_is_umount_for_zygote_system_process_enabled = true; - path_put(&path); - } - pr_info("susfs_is_umount_for_zygote_system_process_enabled: %d\n", susfs_is_umount_for_zygote_system_process_enabled); + if (!kern_path(DATA_ADB_UMOUNT_FOR_ZYGOTE_SYSTEM_PROCESS, 0, &path)) { + susfs_is_umount_for_zygote_system_process_enabled = true; + path_put(&path); + } + pr_info("susfs_is_umount_for_zygote_system_process_enabled: %d\n", susfs_is_umount_for_zygote_system_process_enabled); #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT - if (!kern_path(DATA_ADB_NO_AUTO_ADD_SUS_BIND_MOUNT, 0, &path)) { - susfs_is_auto_add_sus_bind_mount_enabled = false; - path_put(&path); - } - pr_info("susfs_is_auto_add_sus_bind_mount_enabled: %d\n", susfs_is_auto_add_sus_bind_mount_enabled); + if (!kern_path(DATA_ADB_NO_AUTO_ADD_SUS_BIND_MOUNT, 0, &path)) { + susfs_is_auto_add_sus_bind_mount_enabled = false; + path_put(&path); + } + pr_info("susfs_is_auto_add_sus_bind_mount_enabled: %d\n", susfs_is_auto_add_sus_bind_mount_enabled); #endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT - if (!kern_path(DATA_ADB_NO_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT, 0, &path)) { - susfs_is_auto_add_sus_ksu_default_mount_enabled = false; - path_put(&path); - } - pr_info("susfs_is_auto_add_sus_ksu_default_mount_enabled: %d\n", susfs_is_auto_add_sus_ksu_default_mount_enabled); + if (!kern_path(DATA_ADB_NO_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT, 0, &path)) { + susfs_is_auto_add_sus_ksu_default_mount_enabled = false; + path_put(&path); + } + pr_info("susfs_is_auto_add_sus_ksu_default_mount_enabled: %d\n", susfs_is_auto_add_sus_ksu_default_mount_enabled); #endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT - if (!kern_path(DATA_ADB_NO_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT, 0, &path)) { - susfs_is_auto_add_try_umount_for_bind_mount_enabled = false; - path_put(&path); - } - pr_info("susfs_is_auto_add_try_umount_for_bind_mount_enabled: %d\n", susfs_is_auto_add_try_umount_for_bind_mount_enabled); + if (!kern_path(DATA_ADB_NO_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT, 0, &path)) { + susfs_is_auto_add_try_umount_for_bind_mount_enabled = false; + path_put(&path); + } + pr_info("susfs_is_auto_add_try_umount_for_bind_mount_enabled: %d\n", susfs_is_auto_add_try_umount_for_bind_mount_enabled); #endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT } #endif // #ifdef CONFIG_KSU_SUSFS @@ -90,335 +90,335 @@ bool ksu_uid_scanner_enabled = false; // Permission check functions bool only_manager(void) { - return is_manager(); + return is_manager(); } bool only_root(void) { - return current_uid().val == 0; + return current_uid().val == 0; } bool manager_or_root(void) { - return current_uid().val == 0 || is_manager(); + return current_uid().val == 0 || is_manager(); } bool always_allow(void) { - return true; // No permission check + return true; // No permission check } bool allowed_for_su(void) { - bool is_allowed = is_manager() || ksu_is_allow_uid_for_current(current_uid().val); + bool is_allowed = is_manager() || ksu_is_allow_uid_for_current(current_uid().val); #if __SULOG_GATE ksu_sulog_report_permission_check(current_uid().val, current->comm, is_allowed); #endif - return is_allowed; + return is_allowed; } 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); - } - } + 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); + } + } } static int do_grant_root(void __user *arg) { - // we already check uid above on allowed_for_su() + // we already check uid above on allowed_for_su() - pr_info("allow root for: %d\n", current_uid().val); - escape_with_root_profile(); + pr_info("allow root for: %d\n", current_uid().val); + escape_with_root_profile(); - return 0; + return 0; } static int do_get_info(void __user *arg) { - struct ksu_get_info_cmd cmd = {.version = KERNEL_SU_VERSION, .flags = 0}; + struct ksu_get_info_cmd cmd = {.version = KERNEL_SU_VERSION, .flags = 0}; #ifdef MODULE - cmd.flags |= 0x1; + cmd.flags |= 0x1; #endif - if (is_manager()) { - cmd.flags |= 0x2; - } - cmd.features = KSU_FEATURE_MAX; + if (is_manager()) { + cmd.flags |= 0x2; + } + cmd.features = KSU_FEATURE_MAX; - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_version: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_version: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_report_event(void __user *arg) { - struct ksu_report_event_cmd cmd; + struct ksu_report_event_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } - switch (cmd.event) { - case EVENT_POST_FS_DATA: { - static bool post_fs_data_lock = false; - if (!post_fs_data_lock) { - post_fs_data_lock = true; - pr_info("post-fs-data triggered\n"); + switch (cmd.event) { + case EVENT_POST_FS_DATA: { + static bool post_fs_data_lock = false; + if (!post_fs_data_lock) { + post_fs_data_lock = true; + pr_info("post-fs-data triggered\n"); #ifdef CONFIG_KSU_SUSFS - susfs_on_post_fs_data(); - pr_info("susfs_on_post_fs_data triggered\n"); + susfs_on_post_fs_data(); + pr_info("susfs_on_post_fs_data triggered\n"); #endif - on_post_fs_data(); - init_uid_scanner(); -#if __SULOG_GATE - ksu_sulog_init(); + on_post_fs_data(); + init_uid_scanner(); +#if __SULOG_GATE + ksu_sulog_init(); #endif - ksu_dynamic_manager_init(); - } - break; - } - case EVENT_BOOT_COMPLETED: { - static bool boot_complete_lock = false; - if (!boot_complete_lock) { - boot_complete_lock = true; - pr_info("boot_complete triggered\n"); - on_boot_completed(); + ksu_dynamic_manager_init(); + } + break; + } + case EVENT_BOOT_COMPLETED: { + static bool boot_complete_lock = false; + if (!boot_complete_lock) { + boot_complete_lock = true; + pr_info("boot_complete triggered\n"); + on_boot_completed(); #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - susfs_is_boot_completed_triggered = true; + susfs_is_boot_completed_triggered = true; #endif - } - break; - } - case EVENT_MODULE_MOUNTED: { - pr_info("module mounted!\n"); - on_module_mounted(); - break; - } - default: - break; - } + } + break; + } + case EVENT_MODULE_MOUNTED: { + pr_info("module mounted!\n"); + on_module_mounted(); + break; + } + default: + break; + } - return 0; + return 0; } static int do_set_sepolicy(void __user *arg) { - struct ksu_set_sepolicy_cmd cmd; + struct ksu_set_sepolicy_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } - return handle_sepolicy(cmd.cmd, (void __user *)cmd.arg); + return handle_sepolicy(cmd.cmd, (void __user *)cmd.arg); } static int do_check_safemode(void __user *arg) { - struct ksu_check_safemode_cmd cmd; + struct ksu_check_safemode_cmd cmd; - cmd.in_safe_mode = ksu_is_safe_mode(); + cmd.in_safe_mode = ksu_is_safe_mode(); - if (cmd.in_safe_mode) { - pr_warn("safemode enabled!\n"); - } + if (cmd.in_safe_mode) { + pr_warn("safemode enabled!\n"); + } - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("check_safemode: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("check_safemode: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_get_allow_list(void __user *arg) { - struct ksu_get_allow_list_cmd cmd; + struct ksu_get_allow_list_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } - bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, true); + bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, true); - if (!success) { - return -EFAULT; - } + if (!success) { + return -EFAULT; + } - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_allow_list: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_allow_list: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_get_deny_list(void __user *arg) { - struct ksu_get_allow_list_cmd cmd; + struct ksu_get_allow_list_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } - bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, false); + bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, false); - if (!success) { - return -EFAULT; - } + if (!success) { + return -EFAULT; + } - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_deny_list: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_deny_list: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_uid_granted_root(void __user *arg) { - struct ksu_uid_granted_root_cmd cmd; + struct ksu_uid_granted_root_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } - cmd.granted = ksu_is_allow_uid_for_current(cmd.uid); + cmd.granted = ksu_is_allow_uid_for_current(cmd.uid); - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("uid_granted_root: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("uid_granted_root: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_uid_should_umount(void __user *arg) { - struct ksu_uid_should_umount_cmd cmd; + struct ksu_uid_should_umount_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } - cmd.should_umount = ksu_uid_should_umount(cmd.uid); + cmd.should_umount = ksu_uid_should_umount(cmd.uid); - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("uid_should_umount: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("uid_should_umount: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_get_manager_uid(void __user *arg) { - struct ksu_get_manager_uid_cmd cmd; + struct ksu_get_manager_uid_cmd cmd; - cmd.uid = ksu_get_manager_uid(); + cmd.uid = ksu_get_manager_uid(); - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_manager_uid: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_manager_uid: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_get_app_profile(void __user *arg) { - struct ksu_get_app_profile_cmd cmd; + struct ksu_get_app_profile_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("get_app_profile: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("get_app_profile: copy_from_user failed\n"); + return -EFAULT; + } - if (!ksu_get_app_profile(&cmd.profile)) { - return -ENOENT; - } + if (!ksu_get_app_profile(&cmd.profile)) { + return -ENOENT; + } - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_app_profile: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_app_profile: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_set_app_profile(void __user *arg) { - struct ksu_set_app_profile_cmd cmd; + struct ksu_set_app_profile_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("set_app_profile: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("set_app_profile: copy_from_user failed\n"); + return -EFAULT; + } - if (!ksu_set_app_profile(&cmd.profile, true)) { + if (!ksu_set_app_profile(&cmd.profile, true)) { #if __SULOG_GATE - ksu_sulog_report_manager_operation("SET_APP_PROFILE", - current_uid().val, cmd.profile.current_uid); + ksu_sulog_report_manager_operation("SET_APP_PROFILE", + current_uid().val, cmd.profile.current_uid); #endif - return -EFAULT; - } + return -EFAULT; + } - return 0; + return 0; } static int do_get_feature(void __user *arg) { - struct ksu_get_feature_cmd cmd; - bool supported; - int ret; + struct ksu_get_feature_cmd cmd; + bool supported; + int ret; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("get_feature: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("get_feature: copy_from_user failed\n"); + return -EFAULT; + } - ret = ksu_get_feature(cmd.feature_id, &cmd.value, &supported); - cmd.supported = supported ? 1 : 0; + ret = ksu_get_feature(cmd.feature_id, &cmd.value, &supported); + cmd.supported = supported ? 1 : 0; - if (ret && supported) { - pr_err("get_feature: failed for feature %u: %d\n", cmd.feature_id, ret); - return ret; - } + if (ret && supported) { + pr_err("get_feature: failed for feature %u: %d\n", cmd.feature_id, ret); + return ret; + } - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_feature: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_feature: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_set_feature(void __user *arg) { - struct ksu_set_feature_cmd cmd; - int ret; + struct ksu_set_feature_cmd cmd; + int ret; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("set_feature: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("set_feature: copy_from_user failed\n"); + return -EFAULT; + } - ret = ksu_set_feature(cmd.feature_id, cmd.value); - if (ret) { - pr_err("set_feature: failed for feature %u: %d\n", cmd.feature_id, ret); - return ret; - } + ret = ksu_set_feature(cmd.feature_id, cmd.value); + if (ret) { + pr_err("set_feature: failed for feature %u: %d\n", cmd.feature_id, ret); + return ret; + } - return 0; + return 0; } // kcompat for older kernel @@ -428,7 +428,7 @@ static int do_set_feature(void __user *arg) #define getfd_secure anon_inode_getfd_secure #else // technically not a secure inode, but, this is the only way so. -#define getfd_secure(name, ops, data, flags, __unused) \ +#define getfd_secure(name, ops, data, flags, __unused) \ anon_inode_getfd(name, ops, data, flags) #endif @@ -469,7 +469,7 @@ static int do_get_wrapper_fd(void __user *arg) // copy original inode mode wrapper_inode->i_mode = file_inode(f)->i_mode; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || \ defined(KSU_OPTIONAL_SELINUX_INODE) struct inode_security_struct *sec = selinux_inode(wrapper_inode); #else @@ -493,115 +493,115 @@ put_orig_file: static int do_manage_mark(void __user *arg) { - struct ksu_manage_mark_cmd cmd; + struct ksu_manage_mark_cmd cmd; #ifndef CONFIG_KSU_SUSFS - int ret = 0; + int ret = 0; #endif - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("manage_mark: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("manage_mark: copy_from_user failed\n"); + return -EFAULT; + } - switch (cmd.operation) { - case KSU_MARK_GET: { + switch (cmd.operation) { + case KSU_MARK_GET: { #ifndef CONFIG_KSU_SUSFS - // Get task mark status - ret = ksu_get_task_mark(cmd.pid); - if (ret < 0) { - pr_err("manage_mark: get failed for pid %d: %d\n", cmd.pid, ret); - return ret; - } - cmd.result = (u32)ret; - break; + // Get task mark status + ret = ksu_get_task_mark(cmd.pid); + if (ret < 0) { + pr_err("manage_mark: get failed for pid %d: %d\n", cmd.pid, ret); + return ret; + } + cmd.result = (u32)ret; + break; #else - return -EINVAL; + return -EINVAL; #endif - } - case KSU_MARK_MARK: { + } + case KSU_MARK_MARK: { #ifndef CONFIG_KSU_SUSFS - if (cmd.pid == 0) { - ksu_mark_all_process(); - } else { - ret = ksu_set_task_mark(cmd.pid, true); - if (ret < 0) { - pr_err("manage_mark: set_mark failed for pid %d: %d\n", cmd.pid, - ret); - return ret; - } - } + if (cmd.pid == 0) { + ksu_mark_all_process(); + } else { + ret = ksu_set_task_mark(cmd.pid, true); + if (ret < 0) { + pr_err("manage_mark: set_mark failed for pid %d: %d\n", cmd.pid, + ret); + return ret; + } + } #else - pr_info("susfs: cmd: KSU_MARK_MARK => do nothing\n"); + pr_info("susfs: cmd: KSU_MARK_MARK => do nothing\n"); #endif - break; - } - case KSU_MARK_UNMARK: { + break; + } + case KSU_MARK_UNMARK: { #ifndef CONFIG_KSU_SUSFS - if (cmd.pid == 0) { - ksu_unmark_all_process(); - } else { - ret = ksu_set_task_mark(cmd.pid, false); - if (ret < 0) { - pr_err("manage_mark: set_unmark failed for pid %d: %d\n", - cmd.pid, ret); - return ret; - } - } + if (cmd.pid == 0) { + ksu_unmark_all_process(); + } else { + ret = ksu_set_task_mark(cmd.pid, false); + if (ret < 0) { + pr_err("manage_mark: set_unmark failed for pid %d: %d\n", + cmd.pid, ret); + return ret; + } + } #else - pr_info("susfs: cmd: KSU_MARK_UNMARK => do nothing\n"); + pr_info("susfs: cmd: KSU_MARK_UNMARK => do nothing\n"); #endif - break; - } - case KSU_MARK_REFRESH: { + break; + } + case KSU_MARK_REFRESH: { #ifndef CONFIG_KSU_SUSFS - ksu_mark_running_process(); - pr_info("manage_mark: refreshed running processes\n"); + ksu_mark_running_process(); + pr_info("manage_mark: refreshed running processes\n"); #else - pr_info("susfs: cmd: KSU_MARK_REFRESH: do nothing\n"); + pr_info("susfs: cmd: KSU_MARK_REFRESH: do nothing\n"); #endif - break; - } - default: { - pr_err("manage_mark: invalid operation %u\n", cmd.operation); - return -EINVAL; - } - } - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("manage_mark: copy_to_user failed\n"); - return -EFAULT; - } + break; + } + default: { + pr_err("manage_mark: invalid operation %u\n", cmd.operation); + return -EINVAL; + } + } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("manage_mark: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_nuke_ext4_sysfs(void __user *arg) { - struct ksu_nuke_ext4_sysfs_cmd cmd; - char mnt[256]; - long ret; + struct ksu_nuke_ext4_sysfs_cmd cmd; + char mnt[256]; + long ret; - if (copy_from_user(&cmd, arg, sizeof(cmd))) - return -EFAULT; + if (copy_from_user(&cmd, arg, sizeof(cmd))) + return -EFAULT; - if (!cmd.arg) - return -EINVAL; + if (!cmd.arg) + return -EINVAL; - memset(mnt, 0, sizeof(mnt)); + memset(mnt, 0, sizeof(mnt)); - ret = strncpy_from_user(mnt, cmd.arg, sizeof(mnt)); - if (ret < 0) { - pr_err("nuke ext4 copy mnt failed: %ld\\n", ret); - return -EFAULT; // 或者 return ret; - } + ret = strncpy_from_user(mnt, cmd.arg, sizeof(mnt)); + if (ret < 0) { + pr_err("nuke ext4 copy mnt failed: %ld\\n", ret); + return -EFAULT; // 或者 return ret; + } - if (ret == sizeof(mnt)) { - pr_err("nuke ext4 mnt path too long\\n"); - return -ENAMETOOLONG; - } + if (ret == sizeof(mnt)) { + pr_err("nuke ext4 mnt path too long\\n"); + return -ENAMETOOLONG; + } - pr_info("do_nuke_ext4_sysfs: %s\n", mnt); + pr_info("do_nuke_ext4_sysfs: %s\n", mnt); - return nuke_ext4_sysfs(mnt); + return nuke_ext4_sysfs(mnt); } struct list_head mount_list = LIST_HEAD_INIT(mount_list); @@ -609,568 +609,568 @@ DECLARE_RWSEM(mount_list_lock); static int add_try_umount(void __user *arg) { - struct mount_entry *new_entry, *entry, *tmp; - struct ksu_add_try_umount_cmd cmd; - char buf[256] = {0}; + struct mount_entry *new_entry, *entry, *tmp; + struct ksu_add_try_umount_cmd cmd; + char buf[256] = {0}; - if (copy_from_user(&cmd, arg, sizeof cmd)) - return -EFAULT; + if (copy_from_user(&cmd, arg, sizeof cmd)) + return -EFAULT; - switch (cmd.mode) { - case KSU_UMOUNT_WIPE: { - struct mount_entry *entry, *tmp; - down_write(&mount_list_lock); - list_for_each_entry_safe(entry, tmp, &mount_list, list) { - pr_info("wipe_umount_list: removing entry: %s\n", entry->umountable); - list_del(&entry->list); - kfree(entry->umountable); - kfree(entry); - } - up_write(&mount_list_lock); + switch (cmd.mode) { + case KSU_UMOUNT_WIPE: { + struct mount_entry *entry, *tmp; + down_write(&mount_list_lock); + list_for_each_entry_safe(entry, tmp, &mount_list, list) { + pr_info("wipe_umount_list: removing entry: %s\n", entry->umountable); + list_del(&entry->list); + kfree(entry->umountable); + kfree(entry); + } + up_write(&mount_list_lock); - return 0; - } + return 0; + } - case KSU_UMOUNT_ADD: { - long len = strncpy_from_user(buf, (const char __user *)cmd.arg, 256); - if (len <= 0) - return -EFAULT; - - buf[sizeof(buf) - 1] = '\0'; + case KSU_UMOUNT_ADD: { + long len = strncpy_from_user(buf, (const char __user *)cmd.arg, 256); + if (len <= 0) + return -EFAULT; + + buf[sizeof(buf) - 1] = '\0'; - new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); - if (!new_entry) - return -ENOMEM; + new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); + if (!new_entry) + return -ENOMEM; - new_entry->umountable = kstrdup(buf, GFP_KERNEL); - if (!new_entry->umountable) { - kfree(new_entry); - return -1; - } + new_entry->umountable = kstrdup(buf, GFP_KERNEL); + if (!new_entry->umountable) { + kfree(new_entry); + return -1; + } - down_write(&mount_list_lock); + down_write(&mount_list_lock); - // disallow dupes - // if this gets too many, we can consider moving this whole task to a kthread - list_for_each_entry(entry, &mount_list, list) { - if (!strcmp(entry->umountable, buf)) { - pr_info("cmd_add_try_umount: %s is already here!\n", buf); - up_write(&mount_list_lock); - kfree(new_entry->umountable); - kfree(new_entry); - return -1; - } - } + // disallow dupes + // if this gets too many, we can consider moving this whole task to a kthread + list_for_each_entry(entry, &mount_list, list) { + if (!strcmp(entry->umountable, buf)) { + pr_info("cmd_add_try_umount: %s is already here!\n", buf); + up_write(&mount_list_lock); + kfree(new_entry->umountable); + kfree(new_entry); + return -1; + } + } - // now check flags and add - // this also serves as a null check - if (cmd.flags) - new_entry->flags = cmd.flags; - else - new_entry->flags = 0; + // now check flags and add + // this also serves as a null check + if (cmd.flags) + new_entry->flags = cmd.flags; + else + new_entry->flags = 0; - // debug - list_add(&new_entry->list, &mount_list); - up_write(&mount_list_lock); - pr_info("cmd_add_try_umount: %s added!\n", buf); + // debug + list_add(&new_entry->list, &mount_list); + up_write(&mount_list_lock); + pr_info("cmd_add_try_umount: %s added!\n", buf); - return 0; - } + return 0; + } - // this is just strcmp'd wipe anyway - case KSU_UMOUNT_DEL: { - long len = strncpy_from_user(buf, (const char __user *)cmd.arg, sizeof(buf) - 1); - if (len <= 0) - return -EFAULT; - - buf[sizeof(buf) - 1] = '\0'; + // this is just strcmp'd wipe anyway + case KSU_UMOUNT_DEL: { + long len = strncpy_from_user(buf, (const char __user *)cmd.arg, sizeof(buf) - 1); + if (len <= 0) + return -EFAULT; + + buf[sizeof(buf) - 1] = '\0'; - down_write(&mount_list_lock); - list_for_each_entry_safe(entry, tmp, &mount_list, list) { - if (!strcmp(entry->umountable, buf)) { - pr_info("cmd_add_try_umount: entry removed: %s\n", entry->umountable); - list_del(&entry->list); - kfree(entry->umountable); - kfree(entry); - } - } - up_write(&mount_list_lock); - - return 0; - } - - default: { - pr_err("cmd_add_try_umount: invalid operation %u\n", cmd.mode); - return -EINVAL; - } + down_write(&mount_list_lock); + list_for_each_entry_safe(entry, tmp, &mount_list, list) { + if (!strcmp(entry->umountable, buf)) { + pr_info("cmd_add_try_umount: entry removed: %s\n", entry->umountable); + list_del(&entry->list); + kfree(entry->umountable); + kfree(entry); + } + } + up_write(&mount_list_lock); + + return 0; + } + + default: { + pr_err("cmd_add_try_umount: invalid operation %u\n", cmd.mode); + return -EINVAL; + } - } // switch(cmd.mode) - - return 0; + } // switch(cmd.mode) + + return 0; } // 100. GET_FULL_VERSION - Get full version string static int do_get_full_version(void __user *arg) { - struct ksu_get_full_version_cmd cmd = {0}; + struct ksu_get_full_version_cmd cmd = {0}; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full)); + strscpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full)); #else - strlcpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full)); + strlcpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full)); #endif - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_full_version: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_full_version: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } // 101. HOOK_TYPE - Get hook type static int do_get_hook_type(void __user *arg) { - struct ksu_hook_type_cmd cmd = {0}; - const char *type = "Tracepoint"; - + struct ksu_hook_type_cmd cmd = {0}; + const char *type = "Tracepoint"; + #if defined(KSU_MANUAL_HOOK) - type = "Manual"; + type = "Manual"; #elif defined(CONFIG_KSU_SUSFS) - type = "Inline"; + type = "Inline"; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(cmd.hook_type, type, sizeof(cmd.hook_type)); + strscpy(cmd.hook_type, type, sizeof(cmd.hook_type)); #else - strlcpy(cmd.hook_type, type, sizeof(cmd.hook_type)); + strlcpy(cmd.hook_type, type, sizeof(cmd.hook_type)); #endif - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_hook_type: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_hook_type: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } // 102. ENABLE_KPM - Check if KPM is enabled static int do_enable_kpm(void __user *arg) { - struct ksu_enable_kpm_cmd cmd; - - cmd.enabled = IS_ENABLED(CONFIG_KPM); + struct ksu_enable_kpm_cmd cmd; + + cmd.enabled = IS_ENABLED(CONFIG_KPM); - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("enable_kpm: copy_to_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("enable_kpm: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_dynamic_manager(void __user *arg) { - struct ksu_dynamic_manager_cmd cmd; + struct ksu_dynamic_manager_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("dynamic_manager: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("dynamic_manager: copy_from_user failed\n"); + return -EFAULT; + } - int ret = ksu_handle_dynamic_manager(&cmd.config); - if (ret) - return ret; + int ret = ksu_handle_dynamic_manager(&cmd.config); + if (ret) + return ret; - if (cmd.config.operation == DYNAMIC_MANAGER_OP_GET && - copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("dynamic_manager: copy_to_user failed\n"); - return -EFAULT; - } + if (cmd.config.operation == DYNAMIC_MANAGER_OP_GET && + copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("dynamic_manager: copy_to_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_get_managers(void __user *arg) { - struct ksu_get_managers_cmd cmd; + struct ksu_get_managers_cmd cmd; - int ret = ksu_get_active_managers(&cmd.manager_info); - if (ret) - return ret; + int ret = ksu_get_active_managers(&cmd.manager_info); + if (ret) + return ret; - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("get_managers: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_managers: copy_from_user failed\n"); + return -EFAULT; + } - return 0; + return 0; } static int do_enable_uid_scanner(void __user *arg) { - struct ksu_enable_uid_scanner_cmd cmd; + struct ksu_enable_uid_scanner_cmd cmd; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("enable_uid_scanner: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("enable_uid_scanner: copy_from_user failed\n"); + return -EFAULT; + } - switch (cmd.operation) { - case UID_SCANNER_OP_GET_STATUS: { - bool status = ksu_uid_scanner_enabled; - if (copy_to_user((void __user *)cmd.status_ptr, &status, sizeof(status))) { - pr_err("enable_uid_scanner: copy status failed\n"); - return -EFAULT; - } - break; - } - case UID_SCANNER_OP_TOGGLE: { - bool enabled = cmd.enabled; + switch (cmd.operation) { + case UID_SCANNER_OP_GET_STATUS: { + bool status = ksu_uid_scanner_enabled; + if (copy_to_user((void __user *)cmd.status_ptr, &status, sizeof(status))) { + pr_err("enable_uid_scanner: copy status failed\n"); + return -EFAULT; + } + break; + } + case UID_SCANNER_OP_TOGGLE: { + bool enabled = cmd.enabled; - if (enabled == ksu_uid_scanner_enabled) { - pr_info("enable_uid_scanner: no need to change, already %s\n", - enabled ? "enabled" : "disabled"); - break; - } + if (enabled == ksu_uid_scanner_enabled) { + pr_info("enable_uid_scanner: no need to change, already %s\n", + enabled ? "enabled" : "disabled"); + break; + } - if (enabled) { - // Enable UID scanner - int ret = ksu_throne_comm_init(); - if (ret != 0) { - pr_err("enable_uid_scanner: failed to initialize: %d\n", ret); - return -EFAULT; - } - pr_info("enable_uid_scanner: enabled\n"); - } else { - // Disable UID scanner - ksu_throne_comm_exit(); - pr_info("enable_uid_scanner: disabled\n"); - } + if (enabled) { + // Enable UID scanner + int ret = ksu_throne_comm_init(); + if (ret != 0) { + pr_err("enable_uid_scanner: failed to initialize: %d\n", ret); + return -EFAULT; + } + pr_info("enable_uid_scanner: enabled\n"); + } else { + // Disable UID scanner + ksu_throne_comm_exit(); + pr_info("enable_uid_scanner: disabled\n"); + } - ksu_uid_scanner_enabled = enabled; - ksu_throne_comm_save_state(); - break; - } - case UID_SCANNER_OP_CLEAR_ENV: { - // Clear environment (force exit) - ksu_throne_comm_exit(); - ksu_uid_scanner_enabled = false; - ksu_throne_comm_save_state(); - pr_info("enable_uid_scanner: environment cleared\n"); - break; - } - default: - pr_err("enable_uid_scanner: invalid operation\n"); - return -EINVAL; - } + ksu_uid_scanner_enabled = enabled; + ksu_throne_comm_save_state(); + break; + } + case UID_SCANNER_OP_CLEAR_ENV: { + // Clear environment (force exit) + ksu_throne_comm_exit(); + ksu_uid_scanner_enabled = false; + ksu_throne_comm_save_state(); + pr_info("enable_uid_scanner: environment cleared\n"); + break; + } + default: + pr_err("enable_uid_scanner: invalid operation\n"); + return -EINVAL; + } - return 0; + return 0; } #ifdef CONFIG_KSU_MANUAL_SU static bool system_uid_check(void) { - return current_uid().val <= 2000; + return current_uid().val <= 2000; } static int do_manual_su(void __user *arg) { - struct ksu_manual_su_cmd cmd; - struct manual_su_request request; - int res; + struct ksu_manual_su_cmd cmd; + struct manual_su_request request; + int res; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("manual_su: copy_from_user failed\n"); - return -EFAULT; - } + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("manual_su: copy_from_user failed\n"); + return -EFAULT; + } - pr_info("manual_su request, option=%d, uid=%d, pid=%d\n", - cmd.option, cmd.target_uid, cmd.target_pid); + pr_info("manual_su request, option=%d, uid=%d, pid=%d\n", + cmd.option, cmd.target_uid, cmd.target_pid); - memset(&request, 0, sizeof(request)); - request.target_uid = cmd.target_uid; - request.target_pid = cmd.target_pid; + memset(&request, 0, sizeof(request)); + request.target_uid = cmd.target_uid; + request.target_pid = cmd.target_pid; - if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN || - cmd.option == MANUAL_SU_OP_ESCALATE) { - memcpy(request.token_buffer, cmd.token_buffer, sizeof(request.token_buffer)); - } + if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN || + cmd.option == MANUAL_SU_OP_ESCALATE) { + memcpy(request.token_buffer, cmd.token_buffer, sizeof(request.token_buffer)); + } - res = ksu_handle_manual_su_request(cmd.option, &request); + res = ksu_handle_manual_su_request(cmd.option, &request); - if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) { - memcpy(cmd.token_buffer, request.token_buffer, sizeof(cmd.token_buffer)); - if (copy_to_user(arg, &cmd, sizeof(cmd))) { - pr_err("manual_su: copy_to_user failed\n"); - return -EFAULT; - } - } + if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) { + memcpy(cmd.token_buffer, request.token_buffer, sizeof(cmd.token_buffer)); + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("manual_su: copy_to_user failed\n"); + return -EFAULT; + } + } - return res; + return res; } #endif // IOCTL handlers mapping table static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = { - { .cmd = KSU_IOCTL_GRANT_ROOT, .name = "GRANT_ROOT", .handler = do_grant_root, .perm_check = allowed_for_su }, - { .cmd = KSU_IOCTL_GET_INFO, .name = "GET_INFO", .handler = do_get_info, .perm_check = always_allow }, - { .cmd = KSU_IOCTL_REPORT_EVENT, .name = "REPORT_EVENT", .handler = do_report_event, .perm_check = only_root }, - { .cmd = KSU_IOCTL_SET_SEPOLICY, .name = "SET_SEPOLICY", .handler = do_set_sepolicy, .perm_check = only_root }, - { .cmd = KSU_IOCTL_CHECK_SAFEMODE, .name = "CHECK_SAFEMODE", .handler = do_check_safemode, .perm_check = always_allow }, - { .cmd = KSU_IOCTL_GET_ALLOW_LIST, .name = "GET_ALLOW_LIST", .handler = do_get_allow_list, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_GET_DENY_LIST, .name = "GET_DENY_LIST", .handler = do_get_deny_list, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .name = "UID_GRANTED_ROOT", .handler = do_uid_granted_root, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .name = "UID_SHOULD_UMOUNT", .handler = do_uid_should_umount, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_GET_MANAGER_UID, .name = "GET_MANAGER_UID", .handler = do_get_manager_uid, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_GET_APP_PROFILE, .name = "GET_APP_PROFILE", .handler = do_get_app_profile, .perm_check = only_manager }, - { .cmd = KSU_IOCTL_SET_APP_PROFILE, .name = "SET_APP_PROFILE", .handler = do_set_app_profile, .perm_check = only_manager }, - { .cmd = KSU_IOCTL_GET_FEATURE, .name = "GET_FEATURE", .handler = do_get_feature, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_SET_FEATURE, .name = "SET_FEATURE", .handler = do_set_feature, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_GET_WRAPPER_FD, .name = "GET_WRAPPER_FD", .handler = do_get_wrapper_fd, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_MANAGE_MARK, .name = "MANAGE_MARK", .handler = do_manage_mark, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_NUKE_EXT4_SYSFS, .name = "NUKE_EXT4_SYSFS", .handler = do_nuke_ext4_sysfs, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_ADD_TRY_UMOUNT, .name = "ADD_TRY_UMOUNT", .handler = add_try_umount, .perm_check = manager_or_root }, - { .cmd = KSU_IOCTL_GET_FULL_VERSION,.name = "GET_FULL_VERSION", .handler = do_get_full_version, .perm_check = always_allow}, - { .cmd = KSU_IOCTL_HOOK_TYPE,.name = "GET_HOOK_TYPE", .handler = do_get_hook_type, .perm_check = manager_or_root}, - { .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root}, - { .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .name = "SET_DYNAMIC_MANAGER", .handler = do_dynamic_manager, .perm_check = manager_or_root}, - { .cmd = KSU_IOCTL_GET_MANAGERS, .name = "GET_MANAGERS", .handler = do_get_managers, .perm_check = manager_or_root}, - { .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .name = "SET_ENABLE_UID_SCANNER", .handler = do_enable_uid_scanner, .perm_check = manager_or_root}, + { .cmd = KSU_IOCTL_GRANT_ROOT, .name = "GRANT_ROOT", .handler = do_grant_root, .perm_check = allowed_for_su }, + { .cmd = KSU_IOCTL_GET_INFO, .name = "GET_INFO", .handler = do_get_info, .perm_check = always_allow }, + { .cmd = KSU_IOCTL_REPORT_EVENT, .name = "REPORT_EVENT", .handler = do_report_event, .perm_check = only_root }, + { .cmd = KSU_IOCTL_SET_SEPOLICY, .name = "SET_SEPOLICY", .handler = do_set_sepolicy, .perm_check = only_root }, + { .cmd = KSU_IOCTL_CHECK_SAFEMODE, .name = "CHECK_SAFEMODE", .handler = do_check_safemode, .perm_check = always_allow }, + { .cmd = KSU_IOCTL_GET_ALLOW_LIST, .name = "GET_ALLOW_LIST", .handler = do_get_allow_list, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_GET_DENY_LIST, .name = "GET_DENY_LIST", .handler = do_get_deny_list, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .name = "UID_GRANTED_ROOT", .handler = do_uid_granted_root, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .name = "UID_SHOULD_UMOUNT", .handler = do_uid_should_umount, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_GET_MANAGER_UID, .name = "GET_MANAGER_UID", .handler = do_get_manager_uid, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_GET_APP_PROFILE, .name = "GET_APP_PROFILE", .handler = do_get_app_profile, .perm_check = only_manager }, + { .cmd = KSU_IOCTL_SET_APP_PROFILE, .name = "SET_APP_PROFILE", .handler = do_set_app_profile, .perm_check = only_manager }, + { .cmd = KSU_IOCTL_GET_FEATURE, .name = "GET_FEATURE", .handler = do_get_feature, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_SET_FEATURE, .name = "SET_FEATURE", .handler = do_set_feature, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_GET_WRAPPER_FD, .name = "GET_WRAPPER_FD", .handler = do_get_wrapper_fd, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_MANAGE_MARK, .name = "MANAGE_MARK", .handler = do_manage_mark, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_NUKE_EXT4_SYSFS, .name = "NUKE_EXT4_SYSFS", .handler = do_nuke_ext4_sysfs, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_ADD_TRY_UMOUNT, .name = "ADD_TRY_UMOUNT", .handler = add_try_umount, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_GET_FULL_VERSION,.name = "GET_FULL_VERSION", .handler = do_get_full_version, .perm_check = always_allow}, + { .cmd = KSU_IOCTL_HOOK_TYPE,.name = "GET_HOOK_TYPE", .handler = do_get_hook_type, .perm_check = manager_or_root}, + { .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root}, + { .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .name = "SET_DYNAMIC_MANAGER", .handler = do_dynamic_manager, .perm_check = manager_or_root}, + { .cmd = KSU_IOCTL_GET_MANAGERS, .name = "GET_MANAGERS", .handler = do_get_managers, .perm_check = manager_or_root}, + { .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .name = "SET_ENABLE_UID_SCANNER", .handler = do_enable_uid_scanner, .perm_check = manager_or_root}, #ifdef CONFIG_KSU_MANUAL_SU - { .cmd = KSU_IOCTL_MANUAL_SU, .name = "MANUAL_SU", .handler = do_manual_su, .perm_check = system_uid_check}, + { .cmd = KSU_IOCTL_MANUAL_SU, .name = "MANUAL_SU", .handler = do_manual_su, .perm_check = system_uid_check}, #endif #ifdef CONFIG_KPM - { .cmd = KSU_IOCTL_KPM, .name = "KPM_OPERATION", .handler = do_kpm, .perm_check = manager_or_root}, + { .cmd = KSU_IOCTL_KPM, .name = "KPM_OPERATION", .handler = do_kpm, .perm_check = manager_or_root}, #endif - { .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine + { .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine }; #ifndef CONFIG_KSU_SUSFS struct ksu_install_fd_tw { - struct callback_head cb; - int __user *outp; + struct callback_head cb; + int __user *outp; }; static void ksu_install_fd_tw_func(struct callback_head *cb) { - struct ksu_install_fd_tw *tw = container_of(cb, struct ksu_install_fd_tw, cb); - int fd = ksu_install_fd(); - pr_info("[%d] install ksu fd: %d\n", current->pid, fd); + struct ksu_install_fd_tw *tw = container_of(cb, struct ksu_install_fd_tw, cb); + int fd = ksu_install_fd(); + pr_info("[%d] install ksu fd: %d\n", current->pid, fd); - if (copy_to_user(tw->outp, &fd, sizeof(fd))) { - pr_err("install ksu fd reply err\n"); - do_close_fd(fd); - } + if (copy_to_user(tw->outp, &fd, sizeof(fd))) { + pr_err("install ksu fd reply err\n"); + do_close_fd(fd); + } - kfree(tw); + kfree(tw); } // downstream: make sure to pass arg as reference, this can allow us to extend things. int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg) { - struct ksu_install_fd_tw *tw; + struct ksu_install_fd_tw *tw; - if (magic1 != KSU_INSTALL_MAGIC1) - return 0; + if (magic1 != KSU_INSTALL_MAGIC1) + return 0; #ifdef CONFIG_KSU_DEBUG - pr_info("sys_reboot: intercepted call! magic: 0x%x id: %d\n", magic1, magic2); + pr_info("sys_reboot: intercepted call! magic: 0x%x id: %d\n", magic1, magic2); #endif - // Check if this is a request to install KSU fd - if (magic2 == KSU_INSTALL_MAGIC2) { - tw = kzalloc(sizeof(*tw), GFP_ATOMIC); - if (!tw) - return 0; + // Check if this is a request to install KSU fd + if (magic2 == KSU_INSTALL_MAGIC2) { + tw = kzalloc(sizeof(*tw), GFP_ATOMIC); + if (!tw) + return 0; - tw->outp = (int __user *)*arg; - tw->cb.func = ksu_install_fd_tw_func; + tw->outp = (int __user *)*arg; + tw->cb.func = ksu_install_fd_tw_func; - if (task_work_add(current, &tw->cb, TWA_RESUME)) { - kfree(tw); - pr_warn("install fd add task_work failed\n"); - } + if (task_work_add(current, &tw->cb, TWA_RESUME)) { + kfree(tw); + pr_warn("install fd add task_work failed\n"); + } - return 0; - } + return 0; + } - // extensions + // extensions - return 0; + return 0; } #ifdef KSU_KPROBES_HOOK // Reboot hook for installing fd static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int magic1 = (int)PT_REGS_PARM1(real_regs); - int magic2 = (int)PT_REGS_PARM2(real_regs); - int cmd = (int)PT_REGS_PARM3(real_regs); - void __user **arg = (void __user **)&PT_REGS_SYSCALL_PARM4(real_regs); + struct pt_regs *real_regs = PT_REAL_REGS(regs); + int magic1 = (int)PT_REGS_PARM1(real_regs); + int magic2 = (int)PT_REGS_PARM2(real_regs); + int cmd = (int)PT_REGS_PARM3(real_regs); + void __user **arg = (void __user **)&PT_REGS_SYSCALL_PARM4(real_regs); - return ksu_handle_sys_reboot(magic1, magic2, cmd, arg); + return ksu_handle_sys_reboot(magic1, magic2, cmd, arg); } static struct kprobe reboot_kp = { - .symbol_name = REBOOT_SYMBOL, - .pre_handler = reboot_handler_pre, + .symbol_name = REBOOT_SYMBOL, + .pre_handler = reboot_handler_pre, }; #endif #else int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg) { - if (magic1 != KSU_INSTALL_MAGIC1) { - return -EINVAL; - } + if (magic1 != KSU_INSTALL_MAGIC1) { + return -EINVAL; + } - // If magic2 is susfs and current process is root - if (magic2 == SUSFS_MAGIC && current_uid().val == 0) { + // If magic2 is susfs and current process is root + if (magic2 == SUSFS_MAGIC && current_uid().val == 0) { #ifdef CONFIG_KSU_SUSFS_SUS_PATH - if (cmd == CMD_SUSFS_ADD_SUS_PATH) { - susfs_add_sus_path(arg); - return 0; - } - if (cmd == CMD_SUSFS_ADD_SUS_PATH_LOOP) { - susfs_add_sus_path_loop(arg); - return 0; - } - if (cmd == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) { - susfs_set_i_state_on_external_dir(arg); - return 0; - } - if (cmd == CMD_SUSFS_SET_SDCARD_ROOT_PATH) { - susfs_set_i_state_on_external_dir(arg); - return 0; - } + if (cmd == CMD_SUSFS_ADD_SUS_PATH) { + susfs_add_sus_path(arg); + return 0; + } + if (cmd == CMD_SUSFS_ADD_SUS_PATH_LOOP) { + susfs_add_sus_path_loop(arg); + return 0; + } + if (cmd == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) { + susfs_set_i_state_on_external_dir(arg); + return 0; + } + if (cmd == CMD_SUSFS_SET_SDCARD_ROOT_PATH) { + susfs_set_i_state_on_external_dir(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_PATH #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (cmd == CMD_SUSFS_ADD_SUS_MOUNT) { - susfs_add_sus_mount(arg); - return 0; - } - if (cmd == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) { - susfs_set_hide_sus_mnts_for_all_procs(arg); - return 0; - } - if (cmd == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) { - susfs_set_umount_for_zygote_iso_service(arg); - return 0; - } + if (cmd == CMD_SUSFS_ADD_SUS_MOUNT) { + susfs_add_sus_mount(arg); + return 0; + } + if (cmd == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) { + susfs_set_hide_sus_mnts_for_all_procs(arg); + return 0; + } + if (cmd == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) { + susfs_set_umount_for_zygote_iso_service(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT #ifdef CONFIG_KSU_SUSFS_SUS_KSTAT - if (cmd == CMD_SUSFS_ADD_SUS_KSTAT) { - susfs_add_sus_kstat(arg); - return 0; - } - if (cmd == CMD_SUSFS_UPDATE_SUS_KSTAT) { - susfs_update_sus_kstat(arg); - return 0; - } - if (cmd == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) { - susfs_add_sus_kstat(arg); - return 0; - } + if (cmd == CMD_SUSFS_ADD_SUS_KSTAT) { + susfs_add_sus_kstat(arg); + return 0; + } + if (cmd == CMD_SUSFS_UPDATE_SUS_KSTAT) { + susfs_update_sus_kstat(arg); + return 0; + } + if (cmd == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) { + susfs_add_sus_kstat(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT - if (cmd == CMD_SUSFS_ADD_TRY_UMOUNT) { - susfs_add_try_umount(arg); - return 0; - } + if (cmd == CMD_SUSFS_ADD_TRY_UMOUNT) { + susfs_add_try_umount(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT #ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME - if (cmd == CMD_SUSFS_SET_UNAME) { - susfs_set_uname(arg); - return 0; - } + if (cmd == CMD_SUSFS_SET_UNAME) { + susfs_set_uname(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME #ifdef CONFIG_KSU_SUSFS_ENABLE_LOG - if (cmd == CMD_SUSFS_ENABLE_LOG) { - susfs_enable_log(arg); - return 0; - } + if (cmd == CMD_SUSFS_ENABLE_LOG) { + susfs_enable_log(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG #ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG - if (cmd == CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG) { - susfs_set_cmdline_or_bootconfig(arg); - return 0; - } + if (cmd == CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG) { + susfs_set_cmdline_or_bootconfig(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG #ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT - if (cmd == CMD_SUSFS_ADD_OPEN_REDIRECT) { - susfs_add_open_redirect(arg); - return 0; - } + if (cmd == CMD_SUSFS_ADD_OPEN_REDIRECT) { + susfs_add_open_redirect(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT #ifdef CONFIG_KSU_SUSFS_SUS_SU - if (cmd == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) { - susfs_get_sus_su_working_mode(arg); - return 0; - } - if (cmd == CMD_SUSFS_IS_SUS_SU_READY) { - susfs_is_sus_su_ready(arg); - return 0; - } - if (cmd == CMD_SUSFS_SUS_SU) { - susfs_sus_su(arg); - return 0; - } + if (cmd == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) { + susfs_get_sus_su_working_mode(arg); + return 0; + } + if (cmd == CMD_SUSFS_IS_SUS_SU_READY) { + susfs_is_sus_su_ready(arg); + return 0; + } + if (cmd == CMD_SUSFS_SUS_SU) { + susfs_sus_su(arg); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_SU #ifdef CONFIG_KSU_SUSFS_SUS_MAP - if (cmd == CMD_SUSFS_ADD_SUS_MAP) { - susfs_add_sus_map(arg); - return 0; - } + if (cmd == CMD_SUSFS_ADD_SUS_MAP) { + susfs_add_sus_map(arg); + return 0; + } #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MAP - if (cmd == CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING) { - susfs_set_avc_log_spoofing(arg); - return 0; - } - if (cmd == CMD_SUSFS_SHOW_ENABLED_FEATURES) { - susfs_get_enabled_features(arg); - return 0; - } - if (cmd == CMD_SUSFS_SHOW_VARIANT) { - susfs_show_variant(arg); - return 0; - } - if (cmd == CMD_SUSFS_SHOW_VERSION) { - susfs_show_version(arg); - return 0; - } - return 0; - } + if (cmd == CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING) { + susfs_set_avc_log_spoofing(arg); + return 0; + } + if (cmd == CMD_SUSFS_SHOW_ENABLED_FEATURES) { + susfs_get_enabled_features(arg); + return 0; + } + if (cmd == CMD_SUSFS_SHOW_VARIANT) { + susfs_show_variant(arg); + return 0; + } + if (cmd == CMD_SUSFS_SHOW_VERSION) { + susfs_show_version(arg); + return 0; + } + return 0; + } - // Check if this is a request to install KSU fd - if (magic2 == KSU_INSTALL_MAGIC2) { - int fd = ksu_install_fd(); - pr_info("[%d] install ksu fd: %d\n", current->pid, fd); - if (copy_to_user((int *)*arg, &fd, sizeof(fd))) { - pr_err("install ksu fd reply err\n"); - return 0; - } - } - return 0; + // Check if this is a request to install KSU fd + if (magic2 == KSU_INSTALL_MAGIC2) { + int fd = ksu_install_fd(); + pr_info("[%d] install ksu fd: %d\n", current->pid, fd); + if (copy_to_user((int *)*arg, &fd, sizeof(fd))) { + pr_err("install ksu fd reply err\n"); + return 0; + } + } + return 0; } #endif // #ifndef CONFIG_KSU_SUSFS void ksu_supercalls_init(void) { - int i; + int i; - pr_info("KernelSU IOCTL Commands:\n"); - for (i = 0; ksu_ioctl_handlers[i].handler; i++) { - pr_info(" %-18s = 0x%08x\n", ksu_ioctl_handlers[i].name, ksu_ioctl_handlers[i].cmd); - } + pr_info("KernelSU IOCTL Commands:\n"); + for (i = 0; ksu_ioctl_handlers[i].handler; i++) { + pr_info(" %-18s = 0x%08x\n", ksu_ioctl_handlers[i].name, ksu_ioctl_handlers[i].cmd); + } #ifndef CONFIG_KSU_SUSFS #ifdef KSU_KPROBES_HOOK - int rc = register_kprobe(&reboot_kp); - if (rc) { - pr_err("reboot kprobe failed: %d\n", rc); - } else { - pr_info("reboot kprobe registered successfully\n"); - } + int rc = register_kprobe(&reboot_kp); + if (rc) { + pr_err("reboot kprobe failed: %d\n", rc); + } else { + pr_info("reboot kprobe registered successfully\n"); + } #endif #endif } @@ -1179,99 +1179,99 @@ void ksu_supercalls_exit(void) { #ifndef CONFIG_KSU_SUSFS #ifdef KSU_KPROBES_HOOK - unregister_kprobe(&reboot_kp); + unregister_kprobe(&reboot_kp); #endif #else - pr_info("susfs: do nothing\n"); + pr_info("susfs: do nothing\n"); #endif } static inline void ksu_ioctl_audit(unsigned int cmd, const char *cmd_name, uid_t uid, int ret) { #if __SULOG_GATE - const char *result = (ret == 0) ? "SUCCESS" : - (ret == -EPERM) ? "DENIED" : "FAILED"; - ksu_sulog_report_syscall(uid, NULL, cmd_name, result); + const char *result = (ret == 0) ? "SUCCESS" : + (ret == -EPERM) ? "DENIED" : "FAILED"; + ksu_sulog_report_syscall(uid, NULL, cmd_name, result); #endif } // IOCTL dispatcher static long anon_ksu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - void __user *argp = (void __user *)arg; - int i; + void __user *argp = (void __user *)arg; + int i; #ifdef CONFIG_KSU_DEBUG - pr_info("ksu ioctl: cmd=0x%x from uid=%d\n", cmd, current_uid().val); + pr_info("ksu ioctl: cmd=0x%x from uid=%d\n", cmd, current_uid().val); #endif - for (i = 0; ksu_ioctl_handlers[i].handler; i++) { - if (cmd == ksu_ioctl_handlers[i].cmd) { - // Check permission first - if (ksu_ioctl_handlers[i].perm_check && - !ksu_ioctl_handlers[i].perm_check()) { - pr_warn("ksu ioctl: permission denied for cmd=0x%x uid=%d\n", - cmd, current_uid().val); - ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name, - current_uid().val, -EPERM); - return -EPERM; - } - // Execute handler - int ret = ksu_ioctl_handlers[i].handler(argp); - ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name, - current_uid().val, ret); - return ret; - } - } + for (i = 0; ksu_ioctl_handlers[i].handler; i++) { + if (cmd == ksu_ioctl_handlers[i].cmd) { + // Check permission first + if (ksu_ioctl_handlers[i].perm_check && + !ksu_ioctl_handlers[i].perm_check()) { + pr_warn("ksu ioctl: permission denied for cmd=0x%x uid=%d\n", + cmd, current_uid().val); + ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name, + current_uid().val, -EPERM); + return -EPERM; + } + // Execute handler + int ret = ksu_ioctl_handlers[i].handler(argp); + ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name, + current_uid().val, ret); + return ret; + } + } - pr_warn("ksu ioctl: unsupported command 0x%x\n", cmd); - return -ENOTTY; + pr_warn("ksu ioctl: unsupported command 0x%x\n", cmd); + return -ENOTTY; } // File release handler static int anon_ksu_release(struct inode *inode, struct file *filp) { - pr_info("ksu fd released\n"); - return 0; + pr_info("ksu fd released\n"); + return 0; } // File operations structure static const struct file_operations anon_ksu_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = anon_ksu_ioctl, - .compat_ioctl = anon_ksu_ioctl, - .release = anon_ksu_release, + .owner = THIS_MODULE, + .unlocked_ioctl = anon_ksu_ioctl, + .compat_ioctl = anon_ksu_ioctl, + .release = anon_ksu_release, }; // Install KSU fd to current process int ksu_install_fd(void) { - struct file *filp; - int fd; + struct file *filp; + int fd; - // Get unused fd - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) { - pr_err("ksu_install_fd: failed to get unused fd\n"); - return fd; - } + // Get unused fd + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + pr_err("ksu_install_fd: failed to get unused fd\n"); + return fd; + } - // Create anonymous inode file - filp = anon_inode_getfile("[ksu_driver]", &anon_ksu_fops, NULL, O_RDWR | O_CLOEXEC); - if (IS_ERR(filp)) { - pr_err("ksu_install_fd: failed to create anon inode file\n"); - put_unused_fd(fd); - return PTR_ERR(filp); - } + // Create anonymous inode file + filp = anon_inode_getfile("[ksu_driver]", &anon_ksu_fops, NULL, O_RDWR | O_CLOEXEC); + if (IS_ERR(filp)) { + pr_err("ksu_install_fd: failed to create anon inode file\n"); + put_unused_fd(fd); + return PTR_ERR(filp); + } - // Install fd - fd_install(fd, filp); + // Install fd + fd_install(fd, filp); #if __SULOG_GATE - ksu_sulog_report_permission_check(current_uid().val, current->comm, fd >= 0); + ksu_sulog_report_permission_check(current_uid().val, current->comm, fd >= 0); #endif - pr_info("ksu fd installed: %d for pid %d\n", fd, current->pid); + pr_info("ksu fd installed: %d for pid %d\n", fd, current->pid); - return fd; + return fd; } diff --git a/kernel/supercalls.h b/kernel/supercalls.h index a66e4854..aa300285 100644 --- a/kernel/supercalls.h +++ b/kernel/supercalls.h @@ -17,76 +17,76 @@ // Command structures for ioctl struct ksu_become_daemon_cmd { - __u8 token[65]; // Input: daemon token (null-terminated) + __u8 token[65]; // Input: daemon token (null-terminated) }; struct ksu_get_info_cmd { - __u32 version; // Output: KERNEL_SU_VERSION - __u32 flags; // Output: flags (bit 0: MODULE mode) - __u32 features; // Output: max feature ID supported + __u32 version; // Output: KERNEL_SU_VERSION + __u32 flags; // Output: flags (bit 0: MODULE mode) + __u32 features; // Output: max feature ID supported }; struct ksu_report_event_cmd { - __u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc. + __u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc. }; struct ksu_set_sepolicy_cmd { - __u64 cmd; // Input: sepolicy command - __aligned_u64 arg; // Input: sepolicy argument pointer + __u64 cmd; // Input: sepolicy command + __aligned_u64 arg; // Input: sepolicy argument pointer }; struct ksu_check_safemode_cmd { - __u8 in_safe_mode; // Output: true if in safe mode, false otherwise + __u8 in_safe_mode; // Output: true if in safe mode, false otherwise }; struct ksu_get_allow_list_cmd { - __u32 uids[128]; // Output: array of allowed/denied UIDs - __u32 count; // Output: number of UIDs in array - __u8 allow; // Input: true for allow list, false for deny list + __u32 uids[128]; // Output: array of allowed/denied UIDs + __u32 count; // Output: number of UIDs in array + __u8 allow; // Input: true for allow list, false for deny list }; struct ksu_uid_granted_root_cmd { - __u32 uid; // Input: target UID to check - __u8 granted; // Output: true if granted, false otherwise + __u32 uid; // Input: target UID to check + __u8 granted; // Output: true if granted, false otherwise }; struct ksu_uid_should_umount_cmd { - __u32 uid; // Input: target UID to check - __u8 should_umount; // Output: true if should umount, false otherwise + __u32 uid; // Input: target UID to check + __u8 should_umount; // Output: true if should umount, false otherwise }; struct ksu_get_manager_uid_cmd { - __u32 uid; // Output: manager UID + __u32 uid; // Output: manager UID }; struct ksu_get_app_profile_cmd { - struct app_profile profile; // Input/Output: app profile structure + struct app_profile profile; // Input/Output: app profile structure }; struct ksu_set_app_profile_cmd { - struct app_profile profile; // Input: app profile structure + struct app_profile profile; // Input: app profile structure }; struct ksu_get_feature_cmd { - __u32 feature_id; // Input: feature ID (enum ksu_feature_id) - __u64 value; // Output: feature value/state - __u8 supported; // Output: true if feature is supported, false otherwise + __u32 feature_id; // Input: feature ID (enum ksu_feature_id) + __u64 value; // Output: feature value/state + __u8 supported; // Output: true if feature is supported, false otherwise }; struct ksu_set_feature_cmd { - __u32 feature_id; // Input: feature ID (enum ksu_feature_id) - __u64 value; // Input: feature value/state to set + __u32 feature_id; // Input: feature ID (enum ksu_feature_id) + __u64 value; // Input: feature value/state to set }; struct ksu_get_wrapper_fd_cmd { - __u32 fd; // Input: userspace fd - __u32 flags; // Input: flags of userspace fd + __u32 fd; // Input: userspace fd + __u32 flags; // Input: flags of userspace fd }; struct ksu_manage_mark_cmd { - __u32 operation; // Input: KSU_MARK_* - __s32 pid; // Input: target pid (0 for all processes) - __u32 result; // Output: for get operation - mark status or reg_count + __u32 operation; // Input: KSU_MARK_* + __s32 pid; // Input: target pid (0 for all processes) + __u32 result; // Output: for get operation - mark status or reg_count }; #define KSU_MARK_GET 1 @@ -95,7 +95,7 @@ struct ksu_manage_mark_cmd { #define KSU_MARK_REFRESH 4 struct ksu_nuke_ext4_sysfs_cmd { - __aligned_u64 arg; // Input: mnt pointer + __aligned_u64 arg; // Input: mnt pointer }; struct ksu_add_try_umount_cmd { @@ -111,37 +111,37 @@ struct ksu_add_try_umount_cmd { // Other command structures struct ksu_get_full_version_cmd { - char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string + char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string }; struct ksu_hook_type_cmd { - char hook_type[32]; // Output: hook type string + char hook_type[32]; // Output: hook type string }; struct ksu_enable_kpm_cmd { - __u8 enabled; // Output: true if KPM is enabled + __u8 enabled; // Output: true if KPM is enabled }; struct ksu_dynamic_manager_cmd { - struct dynamic_manager_user_config config; // Input/Output: dynamic manager config + struct dynamic_manager_user_config config; // Input/Output: dynamic manager config }; struct ksu_get_managers_cmd { - struct manager_list_info manager_info; // Output: manager list information + struct manager_list_info manager_info; // Output: manager list information }; struct ksu_enable_uid_scanner_cmd { - __u32 operation; // Input: operation type (UID_SCANNER_OP_GET_STATUS, UID_SCANNER_OP_TOGGLE, UID_SCANNER_OP_CLEAR_ENV) - __u32 enabled; // Input: enable or disable (for UID_SCANNER_OP_TOGGLE) - void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS) + __u32 operation; // Input: operation type (UID_SCANNER_OP_GET_STATUS, UID_SCANNER_OP_TOGGLE, UID_SCANNER_OP_CLEAR_ENV) + __u32 enabled; // Input: enable or disable (for UID_SCANNER_OP_TOGGLE) + void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS) }; #ifdef CONFIG_KSU_MANUAL_SU struct ksu_manual_su_cmd { - __u32 option; // Input: operation type (MANUAL_SU_OP_GENERATE_TOKEN, MANUAL_SU_OP_ESCALATE, MANUAL_SU_OP_ADD_PENDING) - __u32 target_uid; // Input: target UID - __u32 target_pid; // Input: target PID - char token_buffer[33]; // Input/Output: token buffer + __u32 option; // Input: operation type (MANUAL_SU_OP_GENERATE_TOKEN, MANUAL_SU_OP_ESCALATE, MANUAL_SU_OP_ADD_PENDING) + __u32 target_uid; // Input: target UID + __u32 target_pid; // Input: target PID + char token_buffer[33]; // Input/Output: token buffer }; #endif @@ -181,10 +181,10 @@ typedef bool (*ksu_perm_check_t)(void); // IOCTL command mapping struct ksu_ioctl_cmd_map { - unsigned int cmd; - const char *name; - ksu_ioctl_handler_t handler; - ksu_perm_check_t perm_check; // Permission check function + unsigned int cmd; + const char *name; + ksu_ioctl_handler_t handler; + ksu_perm_check_t perm_check; // Permission check function }; // Install KSU fd to current process diff --git a/kernel/syscall_hook_manager.c b/kernel/syscall_hook_manager.c index c0c63fa0..58ceaba5 100644 --- a/kernel/syscall_hook_manager.c +++ b/kernel/syscall_hook_manager.c @@ -70,15 +70,15 @@ static void ksu_mark_running_process_locked() continue; } int uid = task_uid(t).val; - const struct cred *cred = get_task_cred(t); + const struct cred *cred = get_task_cred(t); bool ksu_root_process = uid == 0 && is_task_ksu_domain(cred); - bool is_zygote_process = is_zygote(cred); - bool is_shell = uid == 2000; - // before boot completed, we shall mark init for marking zygote - bool is_init = t->pid == 1; + bool is_zygote_process = is_zygote(cred); + bool is_shell = uid == 2000; + // before boot completed, we shall mark init for marking zygote + bool is_init = t->pid == 1; if (ksu_root_process || is_zygote_process || is_shell || is_init - || ksu_is_allow_uid(uid)) { + || ksu_is_allow_uid(uid)) { ksu_set_task_tracepoint_flag(t); pr_info("hook_manager: mark process: pid:%d, uid: %d, comm:%s\n", t->pid, uid, t->comm); @@ -87,7 +87,7 @@ static void ksu_mark_running_process_locked() pr_info("hook_manager: unmark process: pid:%d, uid: %d, comm:%s\n", t->pid, uid, t->comm); } - put_cred(cred); + put_cred(cred); } read_unlock(&tasklist_lock); } @@ -229,38 +229,38 @@ static struct kretprobe *syscall_unregfunc_rp = NULL; static inline bool check_syscall_fastpath(int nr) { - switch (nr) { - case __NR_newfstatat: - case __NR_faccessat: - case __NR_execve: - case __NR_setresuid: - case __NR_clone: + switch (nr) { + case __NR_newfstatat: + case __NR_faccessat: + case __NR_execve: + case __NR_setresuid: + case __NR_clone: #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) - case __NR_clone3: + case __NR_clone3: #endif - return true; - default: - return false; - } + return true; + default: + return false; + } } // Unmark init's child that are not zygote, adbd or ksud int ksu_handle_init_mark_tracker(const char __user **filename_user) { - char path[64]; + char path[64]; - if (unlikely(!filename_user)) - return 0; + if (unlikely(!filename_user)) + return 0; - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + memset(path, 0, sizeof(path)); + ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (likely(strstr(path, "/app_process") == NULL && strstr(path, "/adbd") == NULL && strstr(path, "/ksud") == NULL)) { + if (likely(strstr(path, "/app_process") == NULL && strstr(path, "/adbd") == NULL && strstr(path, "/ksud") == NULL)) { pr_info("hook_manager: unmark %d exec %s", current->pid, path); - ksu_clear_task_tracepoint_flag_if_needed(current); - } + ksu_clear_task_tracepoint_flag_if_needed(current); + } - return 0; + return 0; } #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS @@ -304,14 +304,14 @@ static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id) if (current->pid != 1 && is_init(get_current_cred())) { ksu_handle_init_mark_tracker(filename_user); } else { - ksu_handle_execve_sucompat(filename_user, NULL, NULL, NULL); - } + ksu_handle_execve_sucompat(filename_user, NULL, NULL, NULL); + } return; } } #endif - // Handle setresuid + // Handle setresuid if (id == __NR_setresuid) { uid_t ruid = (uid_t)PT_REGS_PARM1(regs); uid_t euid = (uid_t)PT_REGS_PARM2(regs); diff --git a/kernel/syscall_hook_manager.h b/kernel/syscall_hook_manager.h index 90245c22..f1c698aa 100644 --- a/kernel/syscall_hook_manager.h +++ b/kernel/syscall_hook_manager.h @@ -27,18 +27,18 @@ int ksu_set_task_mark(pid_t pid, bool mark); static inline void ksu_set_task_tracepoint_flag(struct task_struct *t) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) - set_task_syscall_work(t, SYSCALL_TRACEPOINT); + set_task_syscall_work(t, SYSCALL_TRACEPOINT); #else - set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); #endif } static inline void ksu_clear_task_tracepoint_flag(struct task_struct *t) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) - clear_task_syscall_work(t, SYSCALL_TRACEPOINT); + clear_task_syscall_work(t, SYSCALL_TRACEPOINT); #else - clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); #endif } diff --git a/kernel/throne_comm.c b/kernel/throne_comm.c index b4a065d1..dcb5d5e2 100644 --- a/kernel/throne_comm.c +++ b/kernel/throne_comm.c @@ -25,191 +25,191 @@ 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"); + // 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); - } + 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"); + // 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; + 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; - } + 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; - } + 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"); + pr_info("throne state saved: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled"); exit: - filp_close(fp, 0); + 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; + 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; - } + 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; - } + 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"); + 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); + filp_close(fp, 0); } bool ksu_throne_comm_load_state(void) { - return ksu_queue_work(&ksu_state_load_work); + return ksu_queue_work(&ksu_state_load_work); } void ksu_throne_comm_save_state(void) { - ksu_queue_work(&ksu_state_save_work); + 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; + 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); + 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) + 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; + 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; } #ifdef KSU_COMPAT_HAS_PROC_OPS 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, + .proc_open = uid_scanner_open, + .proc_read = seq_read, + .proc_write = uid_scanner_write, + .proc_lseek = seq_lseek, + .proc_release = single_release, }; #else static const struct file_operations uid_scanner_proc_ops = { - .owner = THIS_MODULE, - .open = uid_scanner_open, - .read = seq_read, - .write = uid_scanner_write, - .llseek = seq_lseek, - .release = single_release, + .owner = THIS_MODULE, + .open = uid_scanner_open, + .read = seq_read, + .write = uid_scanner_write, + .llseek = seq_lseek, + .release = single_release, }; #endif 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; + // 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"); + 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; + 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); + do_save_throne_state(NULL); } \ No newline at end of file diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index 49c2310f..9e0477bd 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -25,203 +25,203 @@ static uid_t locked_dynamic_manager_uid = KSU_INVALID_UID; #define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list" struct uid_data { - struct list_head list; - u32 uid; - char package[KSU_MAX_PACKAGE_NAME]; + 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; + 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; + 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; - } + 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; - } + 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'; + 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'; + 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; + 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; + 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; - } + 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; - } + 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; - } + 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; + 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; + 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; + 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; - } - } - } + 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; + 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; + 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; + 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'; + // Copying the package name + strncpy(pkg, second_last_slash + 1, pkg_len); + pkg[pkg_len] = '\0'; - return 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; - } + 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); + 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; - } + // 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; + 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); + 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; - } - } + 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); + 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 (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; - } - } + // 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; + char dirpath[DATA_PATH_LEN]; + int depth; + struct list_head list; }; struct apk_path_hash { - unsigned int hash; - bool exists; - struct list_head list; + 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; + 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. @@ -236,334 +236,334 @@ struct my_dir_context { #endif FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, - int namelen, loff_t off, u64 ino, - unsigned int d_type) + 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]; + 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 (!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 (!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 && 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 = kzalloc(sizeof(struct data_path), GFP_ATOMIC); + if (d_type == DT_DIR && my_ctx->depth > 0 && + (my_ctx->stop && !*my_ctx->stop)) { + struct data_path *data = kzalloc(sizeof(struct data_path), GFP_ATOMIC); - if (!data) { - pr_err("Failed to allocate memory for %s\n", dirpath); - return FILLDIR_ACTOR_CONTINUE; - } + 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; + 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; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) - unsigned int hash = full_name_hash(dirpath, strlen(dirpath)); + unsigned int hash = full_name_hash(dirpath, strlen(dirpath)); #else - unsigned int hash = full_name_hash(NULL, dirpath, strlen(dirpath)); + unsigned int hash = full_name_hash(NULL, dirpath, strlen(dirpath)); #endif - list_for_each_entry(pos, &apk_path_hash_list, list) { - if (hash == pos->hash) { - pos->exists = true; - return FILLDIR_ACTOR_CONTINUE; - } - } + 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); + 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); - } else if (is_manager_apk(dirpath)) { - crown_manager(dirpath, my_ctx->private_data, 0); - *my_ctx->stop = 1; - } + 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); + } else if (is_manager_apk(dirpath)) { + crown_manager(dirpath, my_ctx->private_data, 0); + *my_ctx->stop = 1; + } - struct apk_path_hash *apk_data = kzalloc(sizeof(*apk_data), GFP_ATOMIC); - if (apk_data) { - apk_data->hash = hash; - apk_data->exists = true; - list_add_tail(&apk_data->list, &apk_path_hash_list); - } + struct apk_path_hash *apk_data = kzalloc(sizeof(*apk_data), GFP_ATOMIC); + if (apk_data) { + apk_data->hash = hash; + apk_data->exists = true; + list_add_tail(&apk_data->list, &apk_path_hash_list); + } - if (is_manager_apk(dirpath)) { - // 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 (is_manager_apk(dirpath)) { + // Manager found, clear APK cache list + list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { + list_del(&pos->list); + kfree(pos); + } + } + } + } - return FILLDIR_ACTOR_CONTINUE; + 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; - } + 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); + // 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; + 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; + 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; - } + 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; - } - } + // 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; - } + 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); - } - } + 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); - } - } + // 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; + 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; + 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; } void track_throne(bool prune_only) { - struct list_head uid_list; - struct uid_data *np, *n; - struct file *fp; - char chr = 0; - loff_t pos = 0; - loff_t line_start = 0; - char buf[KSU_MAX_PACKAGE_NAME]; - static bool manager_exist = false; - static bool dynamic_manager_exist = false; - int current_manager_uid = ksu_get_manager_uid() % 100000; + struct list_head uid_list; + struct uid_data *np, *n; + struct file *fp; + char chr = 0; + loff_t pos = 0; + loff_t line_start = 0; + char buf[KSU_MAX_PACKAGE_NAME]; + static bool manager_exist = false; + static bool dynamic_manager_exist = false; + int current_manager_uid = ksu_get_manager_uid() % 100000; - // init uid list head - INIT_LIST_HEAD(&uid_list); + // 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 (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); - goto uid_ready; - } + if (uid_from_um_list(&uid_list) == 0) { + pr_info("Loaded UIDs from %s success\n", KSU_UID_LIST_PATH); + goto uid_ready; + } - pr_warn("%s read failed, fallback to %s\n", - KSU_UID_LIST_PATH, SYSTEM_PACKAGES_LIST_PATH); - } + pr_warn("%s read failed, fallback to %s\n", + KSU_UID_LIST_PATH, SYSTEM_PACKAGES_LIST_PATH); + } - { - fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp)); - return; - } + { + fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp)); + return; + } - for (;;) { - ssize_t count = - ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); - if (count != sizeof(chr)) - break; - if (chr != '\n') - continue; + for (;;) { + ssize_t count = + ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); + if (count != sizeof(chr)) + break; + if (chr != '\n') + continue; - count = ksu_kernel_read_compat(fp, buf, sizeof(buf), - &line_start); - struct uid_data *data = - kzalloc(sizeof(struct uid_data), GFP_ATOMIC); - if (!data) { - filp_close(fp, 0); - goto out; - } + count = ksu_kernel_read_compat(fp, buf, sizeof(buf), + &line_start); + struct uid_data *data = + kzalloc(sizeof(struct uid_data), GFP_ATOMIC); + if (!data) { + filp_close(fp, 0); + goto out; + } - char *tmp = buf; - const char *delim = " "; - char *package = strsep(&tmp, delim); - char *uid = strsep(&tmp, delim); - if (!uid || !package) { - pr_err("update_uid: package or uid is NULL!\n"); - break; - } + char *tmp = buf; + const char *delim = " "; + char *package = strsep(&tmp, delim); + char *uid = strsep(&tmp, delim); + if (!uid || !package) { + pr_err("update_uid: package or uid is NULL!\n"); + break; + } - u32 res; - if (kstrtou32(uid, 10, &res)) { - pr_err("update_uid: uid parse err\n"); - break; - } - data->uid = res; - strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); - list_add_tail(&data->list, &uid_list); - // reset line start - line_start = pos; - } + u32 res; + if (kstrtou32(uid, 10, &res)) { + pr_err("update_uid: uid parse err\n"); + break; + } + data->uid = res; + strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); + list_add_tail(&data->list, &uid_list); + // reset line start + line_start = pos; + } - filp_close(fp, 0); - } + filp_close(fp, 0); + } uid_ready: - if (prune_only) - goto prune; + if (prune_only) + goto prune; - // first, check if manager_uid exist! - list_for_each_entry(np, &uid_list, list) { - if (np->uid == current_manager_uid) { - manager_exist = true; - break; - } - } + // first, check if manager_uid exist! + 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, unlock previous UID: %d\n", - locked_manager_uid); - ksu_invalidate_manager_uid(); - locked_manager_uid = KSU_INVALID_UID; - } + if (!manager_exist && locked_manager_uid != KSU_INVALID_UID) { + pr_info("Manager APK removed, unlock 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) - 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; - } - } + // Check if the Dynamic Manager exists (only check locked UIDs) + 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, unlock previous UID: %d\n", - locked_dynamic_manager_uid); - ksu_remove_manager(locked_dynamic_manager_uid); - locked_dynamic_manager_uid = KSU_INVALID_UID; - } - } + if (!dynamic_manager_exist) { + pr_info("Dynamic manager APK removed, unlock 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; + 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"); - } - + if (need_search) { + pr_info("Searching for manager(s)...\n"); + search_manager("/data/app", 2, &uid_list); + pr_info("Manager search finished\n"); + } + prune: - // then prune the allowlist - ksu_prune_allowlist(is_uid_exist, &uid_list); + // 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); - } + // free uid_list + list_for_each_entry_safe(np, n, &uid_list, list) { + list_del(&np->list); + kfree(np); + } } void ksu_throne_tracker_init(void) { - // nothing to do + // nothing to do } void ksu_throne_tracker_exit(void) { - // nothing to do + // nothing to do } \ No newline at end of file