From afc8b53ca6049c65a917f396c321ff8c8dca3cf8 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Sun, 2 Nov 2025 01:11:38 +0800 Subject: [PATCH] new supercall impl (#511) * refactor: replace throne tracker with ksud token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use snprintf * refactor: new supercall impl - Import the sukisu command * disable seccomp for supercall users * kernel: fmt clear * kernel: Enable macro protection for sulog - Only enabled on kernel versions greater than 5.10.245 * kernel: Refactor kprobe hooks and implement LSM hooks for improved security handling * debug mode * kernel: Add functionality to generate and validate authentication tokens for cmd_su * kernel: Simplified manual SU command processing for code * kernel: replace renameat hook with fsnotify * Revert "refactor: replace throne tracker with ksud token" This reverts commit aa2cbbf. * kernel: fix compile * kernel: fix compile below 6.0 * Fix compile err; Add become_manager * kernel: install fd for manager automaticlly - extend to import the corresponding command * manager: new supercall impl * temp changes for ksud * ksud: fix compile * fix wrong opcode * kernel: fix compile * kernel: Fixed hook type and KPM status retrieval errors * kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10 When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end. Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> * ksud: fix cargo check * manager: Fixed an issue where the KSUD release and user-mode scanning switch failed to function correctly. - kernel: fix spin lock mutual kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10 When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end. kernel: try introduce like susfs's method to fix prctl delay * seccomp: allow reboot * use u32 * update clang-format * 4 spaces save the world * ksud: Fix build on macOS * manager: bump minimal supported kernel. - When get_hook_type is empty, display “Unknown”. * Fix ksud build (#2841) * try fix ksud * fix for macos * remove any * Fix ksud build, take 3 * try fix allowlist * bring lsm hook back * fix: a lot again * Fix ksud build, take 4 (#2846) Remove init_driver_fd function for non-linux/android targets * manager: Return to the native method via KSUd installation * Merge with susfs-mian format --------- Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Co-authored-by: Ylarod Co-authored-by: weishu Co-authored-by: AlexLiuDev233 Co-authored-by: Wang Han <416810799@qq.com> --- kernel/.clang-format | 12 +- kernel/Kconfig | 96 +- kernel/Makefile | 2 + kernel/allowlist.c | 678 ++++----- kernel/apk_sign.c | 574 ++++---- kernel/arch.h | 15 + kernel/core_hook.c | 2429 +++++++++++++------------------- kernel/include/ksu_hook.h | 8 +- kernel/kernel_compat.c | 318 +++-- kernel/kernel_compat.h | 45 +- kernel/ksu.c | 86 +- kernel/ksu.h | 103 +- kernel/ksu_trace.c | 10 +- kernel/ksu_trace.h | 20 +- kernel/ksud.c | 897 ++++++------ kernel/manager.h | 15 +- kernel/manager_sign.h | 4 +- kernel/manual_su.c | 8 +- kernel/pkg_observer.c | 133 ++ kernel/selinux/rules.c | 822 +++++------ kernel/selinux/selinux.c | 248 ++-- kernel/selinux/selinux_defs.h | 16 +- kernel/selinux/sepolicy.c | 1496 ++++++++++---------- kernel/selinux/sepolicy.h | 22 +- kernel/sucompat.c | 454 +++--- kernel/sulog.c | 578 ++++---- kernel/sulog.h | 4 +- kernel/supercalls.c | 609 ++++++++ kernel/supercalls.h | 142 ++ kernel/throne_comm.c | 235 ++- kernel/throne_tracker.c | 7 +- kernel/throne_tracker_legacy.c | 920 ++++++------ 32 files changed, 5762 insertions(+), 5244 deletions(-) create mode 100644 kernel/pkg_observer.c create mode 100644 kernel/supercalls.c create mode 100644 kernel/supercalls.h diff --git a/kernel/.clang-format b/kernel/.clang-format index 10dc5a9a..6453cf96 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: 8 -ContinuationIndentWidth: 8 +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false @@ -501,7 +501,7 @@ IncludeCategories: IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false #IndentPPDirectives: None # Unknown to clang-format-5.0 -IndentWidth: 8 +IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true @@ -511,7 +511,7 @@ MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 -ObjCBlockIndentWidth: 8 +ObjCBlockIndentWidth: 4 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true @@ -543,6 +543,6 @@ SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp03 -TabWidth: 8 -UseTab: Always +TabWidth: 4 +UseTab: Never ... diff --git a/kernel/Kconfig b/kernel/Kconfig index 10c8be90..bdc8c4b1 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -1,42 +1,42 @@ 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 + Enable multi KernelSU manager support config KSU_THRONE_TRACKER_LEGACY - bool "Use legacy throne tracker (packages.list scanning)" - depends on KSU - default n - help - Use legacy throne tracker that scans packages.list for app UIDs. - This is kept for Ultra-Legacy Linux 4.4-3.X kernels which are prone to deadlocks. - Enable this if default scanning deadlocks/crashes on you. + bool "Use legacy throne tracker (packages.list scanning)" + depends on KSU + default n + help + Use legacy throne tracker that scans packages.list for app UIDs. + This is kept for Ultra-Legacy Linux 4.4-3.X kernels which are prone to deadlocks. + Enable this if default scanning deadlocks/crashes on you. config KSU_MANUAL_SU - bool "Use manual su" - depends on KSU - default y - help - Use manual su and authorize the corresponding command line and application via prctl + bool "Use manual su" + depends on KSU + default y + help + Use manual su and authorize the corresponding command line and application via prctl config KSU_ALLOWLIST_WORKAROUND bool "KernelSU Session Keyring Init workaround" @@ -47,23 +47,23 @@ config KSU_ALLOWLIST_WORKAROUND Useful for situations where the SU allowlist is not kept after a reboot config KSU_CMDLINE - bool "Enable KernelSU cmdline" - depends on KSU && KSU != m - default n - help - Enable a cmdline called kernelsu.enabled - Value 1 means enabled, value 0 means disabled. + bool "Enable KernelSU cmdline" + depends on KSU && KSU != m + default n + help + Enable a cmdline called kernelsu.enabled + Value 1 means enabled, value 0 means disabled. 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. choice prompt "KernelSU hook type" @@ -74,21 +74,21 @@ choice config KSU_KPROBES_HOOK bool "Hook KernelSU with Kprobes" - depends on KPROBES - help - If enabled, Hook required KernelSU syscalls with Kernel-probe. + depends on KPROBES + help + If enabled, Hook required KernelSU syscalls with Kernel-probe. config KSU_TRACEPOINT_HOOK bool "Hook KernelSU with Tracepoint" - depends on TRACEPOINTS - help - If enabled, Hook required KernelSU syscalls with Tracepoint. + depends on TRACEPOINTS + help + If enabled, Hook required KernelSU syscalls with Tracepoint. config KSU_MANUAL_HOOK bool "Hook KernelSU manually" - depends on KSU != m - help - If enabled, Hook required KernelSU syscalls with manually-patched function. + depends on KSU != m + help + If enabled, Hook required KernelSU syscalls with manually-patched function. endchoice diff --git a/kernel/Makefile b/kernel/Makefile index 6396789f..0a080d22 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,7 +3,9 @@ kernelsu-objs += allowlist.o kernelsu-objs += dynamic_manager.o kernelsu-objs += apk_sign.o kernelsu-objs += sucompat.o +kernelsu-objs += pkg_observer.o kernelsu-objs += core_hook.o +kernelsu-objs += supercalls.o kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 5fe49f28..659f41a1 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -36,53 +36,53 @@ static int allow_list_pointer __read_mostly = 0; static void remove_uid_from_arr(uid_t uid) { - int *temp_arr; - int i, j; + int *temp_arr; + int i, j; - if (allow_list_pointer == 0) - return; + if (allow_list_pointer == 0) + return; - temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL); - if (temp_arr == NULL) { - pr_err("%s: unable to allocate memory\n", __func__); - return; - } + temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL); + if (temp_arr == NULL) { + pr_err("%s: unable to allocate memory\n", __func__); + return; + } - for (i = j = 0; i < allow_list_pointer; i++) { - if (allow_list_arr[i] == uid) - continue; - temp_arr[j++] = allow_list_arr[i]; - } + for (i = j = 0; i < allow_list_pointer; i++) { + if (allow_list_arr[i] == uid) + continue; + temp_arr[j++] = allow_list_arr[i]; + } - allow_list_pointer = j; + allow_list_pointer = j; - for (; j < ARRAY_SIZE(allow_list_arr); j++) - temp_arr[j] = -1; + for (; j < ARRAY_SIZE(allow_list_arr); j++) + temp_arr[j] = -1; - memcpy(&allow_list_arr, temp_arr, PAGE_SIZE); - kfree(temp_arr); + memcpy(&allow_list_arr, temp_arr, PAGE_SIZE); + kfree(temp_arr); } static void init_default_profiles(void) { - kernel_cap_t full_cap = CAP_FULL_SET; + kernel_cap_t full_cap = CAP_FULL_SET; - default_root_profile.uid = 0; - default_root_profile.gid = 0; - 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)); - default_root_profile.namespaces = 0; - strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); + default_root_profile.uid = 0; + default_root_profile.gid = 0; + 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)); + default_root_profile.namespaces = 0; + strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); - // This means that we will umount modules by default! - default_non_root_profile.umount_modules = true; + // This means that we will umount modules by default! + default_non_root_profile.umount_modules = true; } struct perm_data { - struct list_head list; - struct app_profile profile; + struct list_head list; + struct app_profile profile; }; static struct list_head allow_list; @@ -99,432 +99,432 @@ static bool persistent_allow_list(void); void ksu_show_allow_list(void) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - pr_info("ksu_show_allow_list\n"); - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - pr_info("uid :%d, allow: %d\n", p->profile.current_uid, - p->profile.allow_su); - } + struct perm_data *p = NULL; + struct list_head *pos = NULL; + pr_info("ksu_show_allow_list\n"); + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + pr_info("uid :%d, allow: %d\n", p->profile.current_uid, + p->profile.allow_su); + } } #ifdef CONFIG_KSU_DEBUG static void ksu_grant_root_to_shell(void) { - struct app_profile profile = { - .version = KSU_APP_PROFILE_VER, - .allow_su = true, - .current_uid = 2000, - }; - strcpy(profile.key, "com.android.shell"); - strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); - ksu_set_app_profile(&profile, false); + struct app_profile profile = { + .version = KSU_APP_PROFILE_VER, + .allow_su = true, + .current_uid = 2000, + }; + strcpy(profile.key, "com.android.shell"); + strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); + ksu_set_app_profile(&profile, false); } #endif bool ksu_get_app_profile(struct app_profile *profile) { - 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); - bool uid_match = profile->current_uid == p->profile.current_uid; - if (uid_match) { - // found it, override it with ours - memcpy(profile, &p->profile, sizeof(*profile)); - found = true; - goto exit; - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + bool uid_match = profile->current_uid == p->profile.current_uid; + if (uid_match) { + // found it, override it with ours + memcpy(profile, &p->profile, sizeof(*profile)); + found = true; + goto exit; + } + } exit: - return found; + return found; } static inline bool forbid_system_uid(uid_t uid) { - #define SHELL_UID 2000 - #define SYSTEM_UID 1000 - return uid < SHELL_UID && uid != SYSTEM_UID; + #define SHELL_UID 2000 + #define SYSTEM_UID 1000 + return uid < SHELL_UID && uid != SYSTEM_UID; } static bool profile_valid(struct app_profile *profile) { - if (!profile) { - return false; - } + if (!profile) { + return false; + } - if (profile->version < KSU_APP_PROFILE_VER) { - pr_info("Unsupported profile version: %d\n", profile->version); - return false; - } + if (profile->version < KSU_APP_PROFILE_VER) { + pr_info("Unsupported profile version: %d\n", profile->version); + return false; + } - if (profile->allow_su) { - if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) { - return false; - } + if (profile->allow_su) { + if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) { + return false; + } - if (strlen(profile->rp_config.profile.selinux_domain) == 0) { - return false; - } - } + if (strlen(profile->rp_config.profile.selinux_domain) == 0) { + return false; + } + } - return true; + return true; } bool ksu_set_app_profile(struct app_profile *profile, bool persist) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool result = false; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + bool result = false; - if (!profile_valid(profile)) { - pr_err("Failed to set app profile: invalid profile!\n"); - return false; - } + if (!profile_valid(profile)) { + pr_err("Failed to set app profile: invalid profile!\n"); + return false; + } - list_for_each (pos, &allow_list) { - 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)) { - // found it, just override it all! - memcpy(&p->profile, profile, sizeof(*profile)); - result = true; - goto out; - } - } + list_for_each (pos, &allow_list) { + 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)) { + // found it, just override it all! + memcpy(&p->profile, profile, sizeof(*profile)); + result = true; + goto out; + } + } - // not found, alloc a new node! - p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL); - if (!p) { - pr_err("ksu_set_app_profile alloc failed\n"); - return false; - } + // not found, alloc a new node! + p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL); + if (!p) { + pr_err("ksu_set_app_profile alloc failed\n"); + return false; + } - memcpy(&p->profile, profile, sizeof(*profile)); - if (profile->allow_su) { - pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n", - profile->key, profile->current_uid, - profile->rp_config.profile.gid, - profile->rp_config.profile.selinux_domain); - } else { - pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n", - profile->key, profile->current_uid, - profile->nrp_config.profile.umount_modules); - } - list_add_tail(&p->list, &allow_list); + memcpy(&p->profile, profile, sizeof(*profile)); + if (profile->allow_su) { + pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n", + profile->key, profile->current_uid, + profile->rp_config.profile.gid, + profile->rp_config.profile.selinux_domain); + } else { + pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n", + profile->key, profile->current_uid, + profile->nrp_config.profile.umount_modules); + } + list_add_tail(&p->list, &allow_list); out: - if (profile->current_uid <= BITMAP_UID_MAX) { - if (profile->allow_su) - allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE); - else - allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE)); - } else { - if (profile->allow_su) { - /* - * 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); - return false; - } - allow_list_arr[allow_list_pointer++] = profile->current_uid; - } else { - remove_uid_from_arr(profile->current_uid); - } - } - result = true; + if (profile->current_uid <= BITMAP_UID_MAX) { + if (profile->allow_su) + allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE); + else + allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE)); + } else { + if (profile->allow_su) { + /* + * 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); + return false; + } + allow_list_arr[allow_list_pointer++] = profile->current_uid; + } else { + remove_uid_from_arr(profile->current_uid); + } + } + result = true; - // check if the default profiles is changed, cache it to a single struct to accelerate access. - if (unlikely(!strcmp(profile->key, "$"))) { - // set default non root profile - memcpy(&default_non_root_profile, &profile->nrp_config.profile, - sizeof(default_non_root_profile)); - } + // check if the default profiles is changed, cache it to a single struct to accelerate access. + if (unlikely(!strcmp(profile->key, "$"))) { + // set default non root profile + memcpy(&default_non_root_profile, &profile->nrp_config.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)); - } + if (unlikely(!strcmp(profile->key, "#"))) { + // set default root profile + memcpy(&default_root_profile, &profile->rp_config.profile, + sizeof(default_root_profile)); + } - if (persist) - persistent_allow_list(); + if (persist) + persistent_allow_list(); - return result; + return result; } bool __ksu_is_allow_uid(uid_t uid) { - int i; + int i; - if (unlikely(uid == 0)) { - // already root, but only allow our domain. - return is_ksu_domain(); - } + if (unlikely(uid == 0)) { + // already root, but only allow our domain. + return is_ksu_domain(); + } - if (forbid_system_uid(uid)) { - // do not bother going through the list if it's system - return false; - } + if (forbid_system_uid(uid)) { + // do not bother going through the list if it's system + return false; + } - if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) { - // manager is always allowed! - return true; - } + if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) { + // manager is always allowed! + return true; + } - if (likely(uid <= BITMAP_UID_MAX)) { - return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE))); - } else { - for (i = 0; i < allow_list_pointer; i++) { - if (allow_list_arr[i] == uid) - return true; - } - } + if (likely(uid <= BITMAP_UID_MAX)) { + return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE))); + } else { + for (i = 0; i < allow_list_pointer; i++) { + if (allow_list_arr[i] == uid) + return true; + } + } - return false; + return false; } 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)) { - // we should not umount on manager! - return false; - } - bool found = ksu_get_app_profile(&profile); - if (!found) { - // no app profile found, it must be non root app - return default_non_root_profile.umount_modules; - } - if (profile.allow_su) { - // if found and it is granted to su, we shouldn't umount for it - return false; - } else { - // found an app profile - if (profile.nrp_config.use_default) { - return default_non_root_profile.umount_modules; - } else { - return profile.nrp_config.profile.umount_modules; - } - } + struct app_profile profile = { .current_uid = uid }; + if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) { + // we should not umount on manager! + return false; + } + bool found = ksu_get_app_profile(&profile); + if (!found) { + // no app profile found, it must be non root app + return default_non_root_profile.umount_modules; + } + if (profile.allow_su) { + // if found and it is granted to su, we shouldn't umount for it + return false; + } else { + // found an app profile + if (profile.nrp_config.use_default) { + return default_non_root_profile.umount_modules; + } else { + return profile.nrp_config.profile.umount_modules; + } + } } struct root_profile *ksu_get_root_profile(uid_t uid) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; + struct perm_data *p = NULL; + struct list_head *pos = NULL; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - if (uid == p->profile.current_uid && p->profile.allow_su) { - if (!p->profile.rp_config.use_default) { - return &p->profile.rp_config.profile; - } - } - } + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + if (uid == p->profile.current_uid && p->profile.allow_su) { + if (!p->profile.rp_config.use_default) { + return &p->profile.rp_config.profile; + } + } + } - // use default profile - return &default_root_profile; + // use default profile + return &default_root_profile; } bool ksu_get_allow_list(int *array, int *length, bool allow) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; - int i = 0; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - // pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow); - if (p->profile.allow_su == allow) { - array[i++] = p->profile.current_uid; - } - } - *length = i; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + int i = 0; + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + // pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow); + if (p->profile.allow_su == allow) { + array[i++] = p->profile.current_uid; + } + } + *length = i; - return true; + return true; } static void do_save_allow_list(struct work_struct *work) { - u32 magic = FILE_MAGIC; - u32 version = FILE_FORMAT_VERSION; - struct perm_data *p = NULL; - struct list_head *pos = NULL; - loff_t off = 0; + u32 magic = FILE_MAGIC; + u32 version = FILE_FORMAT_VERSION; + struct perm_data *p = NULL; + struct list_head *pos = NULL; + loff_t off = 0; - struct file *fp = - ksu_filp_open_compat(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)); - return; - } + struct file *fp = + ksu_filp_open_compat(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)); + return; + } - // store magic and version - if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != - sizeof(magic)) { - pr_err("save_allow_list write magic failed.\n"); - goto exit; - } + // store magic and version + if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != + sizeof(magic)) { + pr_err("save_allow_list write magic failed.\n"); + goto exit; + } - if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != - sizeof(version)) { - pr_err("save_allow_list write version failed.\n"); - goto exit; - } + if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != + sizeof(version)) { + pr_err("save_allow_list write version failed.\n"); + goto exit; + } - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - pr_info("save allow list, name: %s uid: %d, allow: %d\n", - p->profile.key, p->profile.current_uid, - p->profile.allow_su); + list_for_each (pos, &allow_list) { + p = list_entry(pos, struct perm_data, list); + pr_info("save allow list, name: %s uid: %d, allow: %d\n", + p->profile.key, p->profile.current_uid, + p->profile.allow_su); - ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile), - &off); - } + ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile), + &off); + } exit: - filp_close(fp, 0); + filp_close(fp, 0); } static void do_load_allow_list(struct work_struct *work) { - loff_t off = 0; - ssize_t ret = 0; - struct file *fp = NULL; - u32 magic; - u32 version; + loff_t off = 0; + ssize_t ret = 0; + struct file *fp = NULL; + u32 magic; + u32 version; #ifdef CONFIG_KSU_DEBUG - // always allow adb shell by default - ksu_grant_root_to_shell(); + // always allow adb shell by default + ksu_grant_root_to_shell(); #endif - // load allowlist now! - fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp)); - return; - } + // load allowlist now! + fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp)); + return; + } - // verify magic - if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != - sizeof(magic) || - magic != FILE_MAGIC) { - pr_err("allowlist file invalid: %d!\n", magic); - goto exit; - } + // verify magic + if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != + 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)) { - pr_err("allowlist read version: %d failed\n", version); - goto exit; - } + if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != + sizeof(version)) { + pr_err("allowlist read version: %d failed\n", version); + goto exit; + } - pr_info("allowlist version: %d\n", version); + pr_info("allowlist version: %d\n", version); - while (true) { - struct app_profile profile; + while (true) { + struct app_profile profile; - ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile), - &off); + ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile), + &off); - if (ret <= 0) { - pr_info("load_allow_list read err: %zd\n", ret); - break; - } + if (ret <= 0) { + pr_info("load_allow_list read err: %zd\n", ret); + break; + } - pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", - profile.key, profile.current_uid, profile.allow_su); - ksu_set_app_profile(&profile, false); - } + pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", + profile.key, profile.current_uid, profile.allow_su); + ksu_set_app_profile(&profile, false); + } exit: - ksu_show_allow_list(); - filp_close(fp, 0); + ksu_show_allow_list(); + filp_close(fp, 0); } void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data) { - struct perm_data *np = NULL; - struct perm_data *n = NULL; + struct perm_data *np = NULL; + struct perm_data *n = NULL; - bool modified = false; - // TODO: use RCU! - mutex_lock(&allowlist_mutex); - list_for_each_entry_safe (np, n, &allow_list, list) { - uid_t uid = np->profile.current_uid; - char *package = np->profile.key; - // we use this uid for special cases, don't prune it! - bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID; - if (!is_preserved_uid && !is_uid_valid(uid, package, data)) { - modified = true; - pr_info("prune uid: %d, package: %s\n", uid, package); - list_del(&np->list); - if (likely(uid <= BITMAP_UID_MAX)) { - allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE)); - } - remove_uid_from_arr(uid); - smp_mb(); - kfree(np); - } - } - mutex_unlock(&allowlist_mutex); + bool modified = false; + // TODO: use RCU! + mutex_lock(&allowlist_mutex); + list_for_each_entry_safe (np, n, &allow_list, list) { + uid_t uid = np->profile.current_uid; + char *package = np->profile.key; + // we use this uid for special cases, don't prune it! + bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID; + if (!is_preserved_uid && !is_uid_valid(uid, package, data)) { + modified = true; + pr_info("prune uid: %d, package: %s\n", uid, package); + list_del(&np->list); + if (likely(uid <= BITMAP_UID_MAX)) { + allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE)); + } + remove_uid_from_arr(uid); + smp_mb(); + kfree(np); + } + } + mutex_unlock(&allowlist_mutex); - if (modified) { - persistent_allow_list(); - } + if (modified) { + persistent_allow_list(); + } } // make sure allow list works cross boot static bool persistent_allow_list(void) { - return ksu_queue_work(&ksu_save_work); + return ksu_queue_work(&ksu_save_work); } bool ksu_load_allow_list(void) { - return ksu_queue_work(&ksu_load_work); + return ksu_queue_work(&ksu_load_work); } void ksu_allowlist_init(void) { - int i; + int i; - BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE); - BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE); + BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE); + BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE); - for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++) - allow_list_arr[i] = -1; + for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++) + allow_list_arr[i] = -1; - INIT_LIST_HEAD(&allow_list); + INIT_LIST_HEAD(&allow_list); - INIT_WORK(&ksu_save_work, do_save_allow_list); - INIT_WORK(&ksu_load_work, do_load_allow_list); + INIT_WORK(&ksu_save_work, do_save_allow_list); + INIT_WORK(&ksu_load_work, do_load_allow_list); - init_default_profiles(); + init_default_profiles(); } void ksu_allowlist_exit(void) { - struct perm_data *np = NULL; - struct perm_data *n = NULL; + struct perm_data *np = NULL; + struct perm_data *n = NULL; - do_save_allow_list(NULL); + do_save_allow_list(NULL); - // free allowlist - mutex_lock(&allowlist_mutex); - list_for_each_entry_safe (np, n, &allow_list, list) { - list_del(&np->list); - kfree(np); - } - mutex_unlock(&allowlist_mutex); + // free allowlist + mutex_lock(&allowlist_mutex); + list_for_each_entry_safe (np, n, &allow_list, list) { + list_del(&np->list); + kfree(np); + } + mutex_unlock(&allowlist_mutex); } #ifdef CONFIG_KSU_MANUAL_SU @@ -555,7 +555,7 @@ bool ksu_temp_grant_root_once(uid_t uid) strcpy(profile.key, default_key); } - profile.rp_config.profile.uid = default_root_profile.uid; + 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)); diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c index 736e86d1..e6238ef3 100644 --- a/kernel/apk_sign.c +++ b/kernel/apk_sign.c @@ -21,68 +21,68 @@ #include "manager_sign.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 #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 = kmalloc(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 = kmalloc(size, GFP_KERNEL); + if (!sdesc) + return ERR_PTR(-ENOMEM); + sdesc->shash.tfm = alg; + return sdesc; } static int calc_hash(struct crypto_shash *alg, const unsigned char *data, - unsigned int datalen, unsigned char *digest) + 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,19 +401,19 @@ 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 diff --git a/kernel/arch.h b/kernel/arch.h index 5207678b..3f15cd07 100644 --- a/kernel/arch.h +++ b/kernel/arch.h @@ -20,6 +20,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) #define PRCTL_SYMBOL "__arm64_sys_prctl" +#define REBOOT_SYMBOL "__arm64_sys_reboot" #define SYS_READ_SYMBOL "__arm64_sys_read" #define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat" #define SYS_FSTATAT64_SYMBOL "__arm64_sys_fstatat64" @@ -28,6 +29,7 @@ #define SYS_EXECVE_COMPAT_SYMBOL "__arm64_compat_sys_execve" #else #define PRCTL_SYMBOL "sys_prctl" +#define REBOOT_SYMBOL "sys_reboot" #define SYS_READ_SYMBOL "sys_read" #define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat" #define SYS_FSTATAT64_SYMBOL "sys_fstatat64" @@ -35,6 +37,11 @@ #define SYS_EXECVE_SYMBOL "sys_execve" #define SYS_EXECVE_COMPAT_SYMBOL "compat_sys_execve" #endif +/*LSM HOOK*/ +#define SECURITY_TASK_FIX_SETUID_SYMBOL "security_task_fix_setuid" +#define INODE_PERMISSION_SYMBOL "security_inode_permission" +#define BPRM_CHECK_SECURITY_SYMBOL "security_bprm_check" +#define TASK_ALLOC_SYMBOL "security_task_alloc" #elif defined(__x86_64__) @@ -53,6 +60,7 @@ #define __PT_IP_REG ip #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) #define PRCTL_SYMBOL "__x64_sys_prctl" +#define REBOOT_SYMBOL "__x64_sys_reboot" #define SYS_READ_SYMBOL "__x64_sys_read" #define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat" #define SYS_FSTATAT64_SYMBOL "__x64_sys_fstatat64" @@ -61,6 +69,7 @@ #define SYS_EXECVE_COMPAT_SYMBOL "__x64_compat_sys_execve" #else #define PRCTL_SYMBOL "sys_prctl" +#define REBOOT_SYMBOL "sys_reboot" #define SYS_READ_SYMBOL "sys_read" #define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat" #define SYS_FSTATAT64_SYMBOL "sys_fstatat64" @@ -68,6 +77,12 @@ #define SYS_EXECVE_SYMBOL "sys_execve" #define SYS_EXECVE_COMPAT_SYMBOL "compat_sys_execve" #endif +/*LSM HOOK*/ +#define SECURITY_TASK_FIX_SETUID_SYMBOL "security_task_fix_setuid" +#define PRCTL_SYMBOL "__arm64_sys_prctl" +#define INODE_PERMISSION_SYMBOL "security_inode_permission" +#define BPRM_CHECK_SECURITY_SYMBOL "security_bprm_check" +#define TASK_ALLOC_SYMBOL "security_task_alloc" #else #ifdef CONFIG_KSU_KPROBES_HOOK diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 27942408..f4227a5a 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -1,13 +1,18 @@ +#include +#include #include +#include #include #include +#include #include #include #include #include #include -#include #include +#include +#include #include #include #include @@ -19,12 +24,10 @@ #include #include #include -#include +#include #include #include -#include -#include #ifndef KSU_HAS_PATH_UMOUNT #include // sys_umount (<4.17) & ksys_umount (4.17+) #endif @@ -50,10 +53,8 @@ #include "ksud.h" #include "manager.h" #include "selinux/selinux.h" -#include "throne_tracker.h" -#include "throne_comm.h" #include "kernel_compat.h" -#include "dynamic_manager.h" +#include "supercalls.h" #include "sulog.h" #ifdef CONFIG_KSU_MANUAL_SU @@ -64,8 +65,6 @@ #include "kpm/kpm.h" #endif -bool ksu_uid_scanner_enabled = false; - #ifdef CONFIG_KSU_SUSFS bool susfs_is_boot_completed_triggered = false; extern u32 susfs_zygote_sid; @@ -99,215 +98,230 @@ extern bool ksu_devpts_hook; #endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU static inline 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 } static inline bool is_some_system_uid(uid_t uid) { - return (uid >= 1000 && uid < 10000); + return (uid >= 1000 && uid < 10000); } static inline bool is_zygote_isolated_service_uid(uid_t uid) { - return ((uid >= 90000 && uid < 100000) || (uid >= 1090000 && uid < 1100000)); + return ((uid >= 90000 && uid < 100000) || (uid >= 1090000 && uid < 1100000)); } static inline bool is_zygote_normal_app_uid(uid_t uid) { - return ((uid >= 10000 && uid < 19999) || (uid >= 1010000 && uid < 1019999)); + return ((uid >= 10000 && uid < 19999) || (uid >= 1010000 && uid < 1019999)); } #endif // #ifdef CONFIG_KSU_SUSFS -static bool ksu_module_mounted = false; +bool ksu_module_mounted = false; -extern int handle_sepolicy(unsigned long arg3, void __user *arg4); +#ifdef CONFIG_COMPAT +bool ksu_is_compat __read_mostly = false; +#endif -bool ksu_su_compat_enabled = true; -extern void ksu_sucompat_init(void); -extern void ksu_sucompat_exit(void); +#ifndef DEVPTS_SUPER_MAGIC +#define DEVPTS_SUPER_MAGIC 0x1cd1 +#endif + +extern int __ksu_handle_devpts(struct inode *inode); // sucompat.c + +#ifdef CONFIG_KSU_MANUAL_SU +static 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); +} +#endif static inline bool is_allow_su(void) { - if (is_manager()) { - // we are manager, allow! - return true; - } - return ksu_is_allow_uid(current_uid().val); + if (is_manager()) { + // we are manager, allow! + return true; + } + return ksu_is_allow_uid(current_uid().val); } static inline bool is_unsupported_uid(uid_t uid) { #define LAST_APPLICATION_UID 19999 - uid_t appid = uid % 100000; - return appid > LAST_APPLICATION_UID; + uid_t appid = uid % 100000; + return appid > LAST_APPLICATION_UID; } #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) { - if (profile->groups_count > KSU_MAX_GROUPS) { - pr_warn("Failed to setgroups, too large group: %d!\n", - profile->uid); - return; - } + if (profile->groups_count > KSU_MAX_GROUPS) { + pr_warn("Failed to setgroups, too large group: %d!\n", + profile->uid); + return; + } - if (profile->groups_count == 1 && profile->groups[0] == 0) { - // setgroup to root and return early. - if (cred->group_info) - put_group_info(cred->group_info); - cred->group_info = get_group_info(&root_groups); - return; - } + if (profile->groups_count == 1 && profile->groups[0] == 0) { + // setgroup to root and return early. + if (cred->group_info) + put_group_info(cred->group_info); + cred->group_info = get_group_info(&root_groups); + return; + } - u32 ngroups = profile->groups_count; - struct group_info *group_info = groups_alloc(ngroups); - if (!group_info) { - pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid); - return; - } + u32 ngroups = profile->groups_count; + struct group_info *group_info = groups_alloc(ngroups); + if (!group_info) { + pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid); + return; + } - int i; - for (i = 0; i < ngroups; i++) { - gid_t gid = profile->groups[i]; - kgid_t kgid = make_kgid(current_user_ns(), gid); - if (!gid_valid(kgid)) { - pr_warn("Failed to setgroups, invalid gid: %d\n", gid); - put_group_info(group_info); - return; - } + int i; + for (i = 0; i < ngroups; i++) { + gid_t gid = profile->groups[i]; + kgid_t kgid = make_kgid(current_user_ns(), gid); + if (!gid_valid(kgid)) { + pr_warn("Failed to setgroups, invalid gid: %d\n", gid); + put_group_info(group_info); + return; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) - group_info->gid[i] = kgid; + group_info->gid[i] = kgid; #else - GROUP_AT(group_info, i) = kgid; + GROUP_AT(group_info, i) = kgid; #endif - } + } - groups_sort(group_info); - set_groups(cred, group_info); - put_group_info(group_info); + groups_sort(group_info); + set_groups(cred, group_info); + put_group_info(group_info); } static void disable_seccomp(struct task_struct *tsk) { - assert_spin_locked(&tsk->sighand->siglock); + assert_spin_locked(&tsk->sighand->siglock); - // disable seccomp + // disable seccomp #if defined(CONFIG_GENERIC_ENTRY) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) - clear_syscall_work(SECCOMP); + LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + clear_syscall_work(SECCOMP); #else - clear_thread_flag(TIF_SECCOMP); + clear_thread_flag(TIF_SECCOMP); #endif #ifdef CONFIG_SECCOMP - tsk->seccomp.mode = 0; - if (tsk->seccomp.filter) { - // 5.9+ have filter_count and use seccomp_filter_release + tsk->seccomp.mode = 0; + if (tsk->seccomp.filter) { + // 5.9+ have filter_count and use seccomp_filter_release #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - seccomp_filter_release(tsk); - atomic_set(&tsk->seccomp.filter_count, 0); + seccomp_filter_release(tsk); + atomic_set(&tsk->seccomp.filter_count, 0); #else - // for 6.11+ kernel support? + // for 6.11+ kernel support? #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) - put_seccomp_filter(tsk); + put_seccomp_filter(tsk); #endif - tsk->seccomp.filter = NULL; + tsk->seccomp.filter = NULL; #endif - } + } #endif } void escape_to_root(void) { - struct cred *newcreds; + struct cred *newcreds; - if (current_euid().val == 0) { - pr_warn("Already root, don't escape!\n"); - return; - } - - newcreds = prepare_creds(); - if (newcreds == NULL) { - pr_err("%s: failed to allocate new cred.\n", __func__); + if (current_euid().val == 0) { + pr_warn("Already root, don't escape!\n"); + return; + } + + newcreds = prepare_creds(); + if (newcreds == NULL) { + pr_err("%s: failed to allocate new cred.\n", __func__); #if __SULOG_GATE - ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed"); + ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed"); #endif - return; - } + return; + } - struct root_profile *profile = - ksu_get_root_profile(newcreds->uid.val); + struct root_profile *profile = + ksu_get_root_profile(newcreds->uid.val); - 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; - BUILD_BUG_ON(sizeof(profile->capabilities.effective) != - sizeof(kernel_cap_t)); + BUILD_BUG_ON(sizeof(profile->capabilities.effective) != + sizeof(kernel_cap_t)); - // setup capabilities - // we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process - // we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec! - u64 cap_for_ksud = - profile->capabilities.effective | CAP_DAC_READ_SEARCH; - memcpy(&newcreds->cap_effective, &cap_for_ksud, - 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 capabilities + // we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process + // we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec! + u64 cap_for_ksud = + profile->capabilities.effective | CAP_DAC_READ_SEARCH; + memcpy(&newcreds->cap_effective, &cap_for_ksud, + 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); - commit_creds(newcreds); + setup_groups(profile, newcreds); + commit_creds(newcreds); - spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(current); - spin_unlock_irq(¤t->sighand->siglock); + spin_lock_irq(¤t->sighand->siglock); + disable_seccomp(current); + spin_unlock_irq(¤t->sighand->siglock); - setup_selinux(profile->selinux_domain); + 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 } @@ -315,178 +329,135 @@ void escape_to_root(void) static void disable_seccomp_for_task(struct task_struct *tsk) { - if (!tsk->seccomp.filter && tsk->seccomp.mode == SECCOMP_MODE_DISABLED) - return; + if (!tsk->seccomp.filter && tsk->seccomp.mode == SECCOMP_MODE_DISABLED) + return; - if (WARN_ON(!spin_is_locked(&tsk->sighand->siglock))) - return; + if (WARN_ON(!spin_is_locked(&tsk->sighand->siglock))) + return; #ifdef CONFIG_SECCOMP - tsk->seccomp.mode = 0; - if (tsk->seccomp.filter) { + tsk->seccomp.mode = 0; + if (tsk->seccomp.filter) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) - seccomp_filter_release(tsk); - atomic_set(&tsk->seccomp.filter_count, 0); + seccomp_filter_release(tsk); + atomic_set(&tsk->seccomp.filter_count, 0); #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_irq(&target_task->sighand->siglock); - disable_seccomp_for_task(target_task); - spin_unlock_irq(&target_task->sighand->siglock); - } + if (target_task->sighand) { + spin_lock_irq(&target_task->sighand->siglock); + disable_seccomp_for_task(target_task); + spin_unlock_irq(&target_task->sighand->siglock); + } - 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) { - __ksu_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) { + __ksu_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 - 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 -int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) -{ - if (!current->mm) { - // skip kernel threads - return 0; - } - - if (current_uid().val != 1000) { - // skip non system uid - return 0; - } - - if (!old_dentry || !new_dentry) { - return 0; - } - - // /data/system/packages.list.tmp -> /data/system/packages.list - if (strcmp(new_dentry->d_iname, "packages.list")) { - return 0; - } - - char path[128]; - char *buf = dentry_path_raw(new_dentry, path, sizeof(path)); - if (IS_ERR(buf)) { - pr_err("dentry_path_raw failed.\n"); - return 0; - } - - if (!strstr(buf, "/system/packages.list")) { - return 0; - } - pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname, - new_dentry->d_iname, buf); - - if (ksu_uid_scanner_enabled) { - ksu_request_userspace_scan(); - } - - track_throne(); - - return 0; -} - #ifdef CONFIG_EXT4_FS static void nuke_ext4_sysfs(void) { - struct path path; - int err = kern_path("/data/adb/modules", 0, &path); - if (err) { - pr_err("nuke path err: %d\n", err); - return; - } + struct path path; + int err = kern_path("/data/adb/modules", 0, &path); + if (err) { + pr_err("nuke path err: %d\n", err); + return; + } - 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; - } + 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; + } - ext4_unregister_sysfs(sb); - path_put(&path); + ext4_unregister_sysfs(sb); + path_put(&path); } #else static inline void nuke_ext4_sysfs(void) @@ -496,823 +467,383 @@ static inline void nuke_ext4_sysfs(void) static bool is_system_bin_su() { - if (!current->mm || current->in_execve) { - return 0; - } + if (!current->mm || current->in_execve) { + return 0; + } - // quick af check - return (current->mm->exe_file && !strcmp(current->mm->exe_file->f_path.dentry->d_name.name, "su")); + // quick af check + return (current->mm->exe_file && !strcmp(current->mm->exe_file->f_path.dentry->d_name.name, "su")); } #ifdef CONFIG_KSU_MANUAL_SU static bool is_system_uid(void) { - if (!current->mm || current->in_execve) { - return 0; - } - - uid_t caller_uid = current_uid().val; - return caller_uid <= 2000; + if (!current->mm || current->in_execve) { + return 0; + } + + uid_t caller_uid = current_uid().val; + return caller_uid <= 2000; } #endif -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); - } - } -} - #if __SULOG_GATE static void sulog_prctl_cmd(uid_t uid, unsigned long cmd) { - const char *name = NULL; + const char *name = NULL; - switch (cmd) { - case CMD_GRANT_ROOT: name = "prctl_grant_root"; break; - case CMD_BECOME_MANAGER: name = "prctl_become_manager"; break; - case CMD_GET_VERSION: name = "prctl_get_version"; break; - case CMD_GET_FULL_VERSION: name = "prctl_get_full_version"; break; - case CMD_SET_SEPOLICY: name = "prctl_set_sepolicy"; break; - case CMD_CHECK_SAFEMODE: name = "prctl_check_safemode"; break; - case CMD_GET_ALLOW_LIST: name = "prctl_get_allow_list"; break; - case CMD_GET_DENY_LIST: name = "prctl_get_deny_list"; break; - case CMD_UID_GRANTED_ROOT: name = "prctl_uid_granted_root"; break; - case CMD_UID_SHOULD_UMOUNT: name = "prctl_uid_should_umount"; break; - case CMD_IS_SU_ENABLED: name = "prctl_is_su_enabled"; break; - case CMD_ENABLE_SU: name = "prctl_enable_su"; break; + switch (cmd) { #ifdef CONFIG_KPM - case CMD_ENABLE_KPM: name = "prctl_enable_kpm"; break; + case CMD_ENABLE_KPM: name = "prctl_enable_kpm"; break; #endif - case CMD_HOOK_TYPE: name = "prctl_hook_type"; break; - case CMD_DYNAMIC_MANAGER: name = "prctl_dynamic_manager"; break; - case CMD_GET_MANAGERS: name = "prctl_get_managers"; break; - case CMD_ENABLE_UID_SCANNER: name = "prctl_enable_uid_scanner"; break; - case CMD_REPORT_EVENT: name = "prctl_report_event"; break; - case CMD_SET_APP_PROFILE: name = "prctl_set_app_profile"; break; - case CMD_GET_APP_PROFILE: name = "prctl_get_app_profile"; break; - #ifdef CONFIG_KSU_MANUAL_SU - case CMD_MANUAL_SU_REQUEST: name = "prctl_manual_su_request"; break; + case CMD_MANUAL_SU_REQUEST: name = "prctl_manual_su_request"; break; #endif #ifdef CONFIG_KSU_SUSFS - case CMD_SUSFS_ADD_SUS_PATH: name = "prctl_susfs_add_sus_path"; break; - case CMD_SUSFS_ADD_SUS_PATH_LOOP: name = "prctl_susfs_add_sus_path_loop"; break; - case CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH: name = "prctl_susfs_set_android_data_root_path"; break; - case CMD_SUSFS_SET_SDCARD_ROOT_PATH: name = "prctl_susfs_set_sdcard_root_path"; break; - case CMD_SUSFS_ADD_SUS_MOUNT: name = "prctl_susfs_add_sus_mount"; break; - case CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS: name = "prctl_susfs_hide_sus_mnts_for_all_procs"; break; - case CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE: name = "prctl_susfs_umount_for_zygote_iso_service"; break; - case CMD_SUSFS_ADD_SUS_KSTAT: name = "prctl_susfs_add_sus_kstat"; break; - case CMD_SUSFS_UPDATE_SUS_KSTAT: name = "prctl_susfs_update_sus_kstat"; break; - case CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY: name = "prctl_susfs_add_sus_kstat_statically"; break; - case CMD_SUSFS_ADD_TRY_UMOUNT: name = "prctl_susfs_add_try_umount"; break; - case CMD_SUSFS_SET_UNAME: name = "prctl_susfs_set_uname"; break; - case CMD_SUSFS_ENABLE_LOG: name = "prctl_susfs_enable_log"; break; - case CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG: name = "prctl_susfs_set_cmdline_or_bootconfig"; break; - case CMD_SUSFS_ADD_OPEN_REDIRECT: name = "prctl_susfs_add_open_redirect"; break; - case CMD_SUSFS_SHOW_VERSION: name = "prctl_susfs_show_version"; break; - case CMD_SUSFS_SHOW_ENABLED_FEATURES: name = "prctl_susfs_show_enabled_features"; break; - case CMD_SUSFS_SHOW_VARIANT: name = "prctl_susfs_show_variant"; break; + case CMD_SUSFS_ADD_SUS_PATH: name = "prctl_susfs_add_sus_path"; break; + case CMD_SUSFS_ADD_SUS_PATH_LOOP: name = "prctl_susfs_add_sus_path_loop"; break; + case CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH: name = "prctl_susfs_set_android_data_root_path"; break; + case CMD_SUSFS_SET_SDCARD_ROOT_PATH: name = "prctl_susfs_set_sdcard_root_path"; break; + case CMD_SUSFS_ADD_SUS_MOUNT: name = "prctl_susfs_add_sus_mount"; break; + case CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS: name = "prctl_susfs_hide_sus_mnts_for_all_procs"; break; + case CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE: name = "prctl_susfs_umount_for_zygote_iso_service"; break; + case CMD_SUSFS_ADD_SUS_KSTAT: name = "prctl_susfs_add_sus_kstat"; break; + case CMD_SUSFS_UPDATE_SUS_KSTAT: name = "prctl_susfs_update_sus_kstat"; break; + case CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY: name = "prctl_susfs_add_sus_kstat_statically"; break; + case CMD_SUSFS_ADD_TRY_UMOUNT: name = "prctl_susfs_add_try_umount"; break; + case CMD_SUSFS_SET_UNAME: name = "prctl_susfs_set_uname"; break; + case CMD_SUSFS_ENABLE_LOG: name = "prctl_susfs_enable_log"; break; + case CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG: name = "prctl_susfs_set_cmdline_or_bootconfig"; break; + case CMD_SUSFS_ADD_OPEN_REDIRECT: name = "prctl_susfs_add_open_redirect"; break; + case CMD_SUSFS_SHOW_VERSION: name = "prctl_susfs_show_version"; break; + case CMD_SUSFS_SHOW_ENABLED_FEATURES: name = "prctl_susfs_show_enabled_features"; break; + case CMD_SUSFS_SHOW_VARIANT: name = "prctl_susfs_show_variant"; break; #ifdef CONFIG_KSU_SUSFS_SUS_SU - case CMD_SUSFS_SUS_SU: name = "prctl_susfs_sus_su"; break; - case CMD_SUSFS_IS_SUS_SU_READY: name = "prctl_susfs_is_sus_su_ready"; break; - case CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE: name = "prctl_susfs_show_sus_su_working_mode"; break; + case CMD_SUSFS_SUS_SU: name = "prctl_susfs_sus_su"; break; + case CMD_SUSFS_IS_SUS_SU_READY: name = "prctl_susfs_is_sus_su_ready"; break; + case CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE: name = "prctl_susfs_show_sus_su_working_mode"; break; #endif - case CMD_SUSFS_ADD_SUS_MAP: name = "prctl_susfs_add_sus_map"; break; - case CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING: name = "prctl_susfs_enable_avc_log_spoofing"; break; + case CMD_SUSFS_ADD_SUS_MAP: name = "prctl_susfs_add_sus_map"; break; + case CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING: name = "prctl_susfs_enable_avc_log_spoofing"; break; #endif - default: name = "prctl_unknown"; break; - } + default: name = "prctl_unknown"; break; + } - ksu_sulog_report_syscall(uid, NULL, name, NULL); + ksu_sulog_report_syscall(uid, NULL, name, NULL); } #endif int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) + unsigned long arg4, unsigned long arg5) { - bool is_manual_su_cmd = false; + bool is_manual_su_cmd = false; #ifdef CONFIG_KSU_MANUAL_SU - is_manual_su_cmd = (arg2 == CMD_MANUAL_SU_REQUEST); + is_manual_su_cmd = (arg2 == CMD_MANUAL_SU_REQUEST); #endif #ifdef CONFIG_KSU_SUSFS - bool saved_umount_flag = false; + bool saved_umount_flag = false; #ifdef CONFIG_KSU_MANUAL_SU if (is_manual_su_cmd || is_system_uid()) { saved_umount_flag = test_and_clear_ti_thread_flag(¤t->thread_info, TIF_PROC_UMOUNTED); } #endif - // - We straight up check if process is supposed to be umounted, return 0 if so - // - This is to prevent side channel attack as much as possible + // - We straight up check if process is supposed to be umounted, return 0 if so + // - This is to prevent side channel attack as much as possible if (likely(!saved_umount_flag && susfs_is_current_proc_umounted())) return 0; #endif - // if success, we modify the arg5 as result! - u32 *result = (u32 *)arg5; - u32 reply_ok = KERNEL_SU_OPTION; + // if success, we modify the arg5 as result! + __maybe_unused u32 *result = (u32 *)arg5; + __maybe_unused u32 reply_ok = KERNEL_SU_OPTION; - if (KERNEL_SU_OPTION != option) { - return 0; - } + if (KERNEL_SU_OPTION != option) { + return 0; + } - // TODO: find it in throne tracker! - uid_t current_uid_val = current_uid().val; - uid_t manager_uid = ksu_get_manager_uid(); - if (current_uid_val != manager_uid && - current_uid_val % 100000 == manager_uid) { - ksu_set_manager_uid(current_uid_val); - } - - bool from_root = 0 == current_uid().val; - bool from_manager = is_manager(); - + bool from_root = 0 == current_uid().val; + bool from_manager = is_manager(); + #if __SULOG_GATE - sulog_prctl_cmd(current_uid().val, arg2); + sulog_prctl_cmd(current_uid().val, arg2); #endif - DONT_GET_SMART(); - if (!from_root && !from_manager - && !(is_manual_su_cmd ? is_system_uid(): - (is_allow_su() && is_system_bin_su()))) { - // only root or manager can access this interface - return 0; - } + DONT_GET_SMART(); + if (!from_root && !from_manager + && !(is_manual_su_cmd ? is_system_uid(): + (is_allow_su() && is_system_bin_su()))) { + // only root or manager can access this interface + return 0; + } #ifdef CONFIG_KSU_DEBUG - pr_info("option: 0x%x, cmd: %ld\n", option, arg2); + pr_info("option: 0x%x, cmd: %ld\n", option, arg2); #endif - if (arg2 == CMD_BECOME_MANAGER) { - if (from_manager) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("become_manager: prctl reply error\n"); - } - return 0; - } - return 0; - } + #ifdef CONFIG_KPM + if(sukisu_is_kpm_control_code(arg2)) { + int res; - if (arg2 == CMD_GRANT_ROOT) { -#if __SULOG_GATE - bool is_allowed = is_allow_su(); - ksu_sulog_report_permission_check(current_uid().val, current->comm, is_allowed); - if (is_allowed) { -#else - if (is_allow_su()) { + pr_info("KPM: calling before arg2=%d\n", (int) arg2); + + res = sukisu_handle_kpm(arg2, arg3, arg4, arg5); + + return 0; + } #endif - pr_info("allow root for: %d\n", current_uid().val); - escape_to_root(); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("grant_root: prctl reply error\n"); - } - } - return 0; - } - - // Both root manager and root processes should be allowed to get version - if (arg2 == CMD_GET_VERSION) { - u32 version = KERNEL_SU_VERSION; - if (copy_to_user(arg3, &version, sizeof(version))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - u32 version_flags = 2; -#ifdef MODULE - version_flags |= 0x1; -#endif - if (arg4 && - copy_to_user(arg4, &version_flags, sizeof(version_flags))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - // Allow root manager to get full version strings - if (arg2 == CMD_GET_FULL_VERSION) { - char ksu_version_full[KSU_FULL_VERSION_STRING] = {0}; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(ksu_version_full, KSU_VERSION_FULL, KSU_FULL_VERSION_STRING); -#else - strlcpy(ksu_version_full, KSU_VERSION_FULL, KSU_FULL_VERSION_STRING); -#endif - if (copy_to_user((void __user *)arg3, ksu_version_full, KSU_FULL_VERSION_STRING)) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - return -EFAULT; - } - return 0; - } - - // Allow the root manager to configure dynamic manageratures - if (arg2 == CMD_DYNAMIC_MANAGER) { - if (!from_root && !from_manager) { - return 0; - } - - struct dynamic_manager_user_config config; - - if (copy_from_user(&config, (void __user *)arg3, sizeof(config))) { - pr_err("copy dynamic manager config failed\n"); - return 0; - } - - int ret = ksu_handle_dynamic_manager(&config); - - if (ret == 0 && config.operation == DYNAMIC_MANAGER_OP_GET) { - if (copy_to_user((void __user *)arg3, &config, sizeof(config))) { - pr_err("copy dynamic manager config back failed\n"); - return 0; - } - } - - if (ret == 0) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("dynamic_manager: prctl reply error\n"); - } - } - return 0; - } - - // Allow root manager to get active managers - if (arg2 == CMD_GET_MANAGERS) { - if (!from_root && !from_manager) { - return 0; - } - - struct manager_list_info manager_info; - int ret = ksu_get_active_managers(&manager_info); - - if (ret == 0) { - if (copy_to_user((void __user *)arg3, &manager_info, sizeof(manager_info))) { - pr_err("copy manager list failed\n"); - return 0; - } - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("get_managers: prctl reply error\n"); - } - } - return 0; - } - - if (arg2 == CMD_REPORT_EVENT) { - if (!from_root) { - return 0; - } - switch (arg3) { - 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(); -#endif - on_post_fs_data(); -#if __SULOG_GATE - ksu_sulog_init(); -#endif - // Initialize UID scanner if enabled - init_uid_scanner(); - // Initializing Dynamic Signatures - ksu_dynamic_manager_init(); - pr_info("Dynamic sign config loaded during post-fs-data\n"); - } - break; - } - case EVENT_BOOT_COMPLETED: { - static bool boot_complete_lock = false; - if (!boot_complete_lock) { - boot_complete_lock = true; - pr_info("boot_complete triggered\n"); -#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - susfs_is_boot_completed_triggered = true; -#endif - - } - break; - } - case EVENT_MODULE_MOUNTED: { - ksu_module_mounted = true; - pr_info("module mounted!\n"); - nuke_ext4_sysfs(); - break; - } - default: - break; - } - return 0; - } - - if (arg2 == CMD_SET_SEPOLICY) { - if (!from_root) { - return 0; - } - if (!handle_sepolicy(arg3, arg4)) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("sepolicy: prctl reply error\n"); - } - } - - return 0; - } - - if (arg2 == CMD_CHECK_SAFEMODE) { - if (ksu_is_safe_mode()) { - pr_warn("safemode enabled!\n"); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("safemode: prctl reply error\n"); - } - } - return 0; - } - - if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) { - u32 array[128]; - u32 array_length; - bool success = ksu_get_allow_list(array, &array_length, - arg2 == CMD_GET_ALLOW_LIST); - if (success) { - if (!copy_to_user(arg4, &array_length, - sizeof(array_length)) && - !copy_to_user(arg3, array, - sizeof(u32) * array_length)) { - if (copy_to_user(result, &reply_ok, - sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", - arg2); - } - } else { - pr_err("prctl copy allowlist error\n"); - } - } - return 0; - } - - if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) { - uid_t target_uid = (uid_t)arg3; - bool allow = false; - if (arg2 == CMD_UID_GRANTED_ROOT) { - allow = ksu_is_allow_uid(target_uid); - } else if (arg2 == CMD_UID_SHOULD_UMOUNT) { - allow = ksu_uid_should_umount(target_uid); - } else { - pr_err("unknown cmd: %lu\n", arg2); - } - if (!copy_to_user(arg4, &allow, sizeof(allow))) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - } else { - pr_err("prctl copy err, cmd: %lu\n", arg2); - } - return 0; - } - -#ifdef CONFIG_KPM - // ADD: 添加KPM模块控制 - if(sukisu_is_kpm_control_code(arg2)) { - int res; - - pr_info("KPM: calling before arg2=%d\n", (int) arg2); - - res = sukisu_handle_kpm(arg2, arg3, arg4, arg5); - - return 0; - } -#endif - - if (arg2 == CMD_ENABLE_SU) { - bool enabled = (arg3 != 0); - if (enabled == ksu_su_compat_enabled) { - pr_info("cmd enable su but no need to change.\n"); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {// return the reply_ok directly - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - if (enabled) { -#ifdef CONFIG_KSU_SUSFS_SUS_SU - // We disable all sus_su hook whenever user toggle on su_kps - susfs_is_sus_su_hooks_enabled = false; - ksu_devpts_hook = false; - susfs_sus_su_working_mode = SUS_SU_DISABLED; -#endif - ksu_sucompat_init(); - } else { - ksu_sucompat_exit(); - } - ksu_su_compat_enabled = enabled; - - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - - return 0; - } - - // Check if kpm is enabled - if (arg2 == CMD_ENABLE_KPM) { - bool KPM_Enabled = IS_ENABLED(CONFIG_KPM); - if (copy_to_user((void __user *)arg3, &KPM_Enabled, sizeof(KPM_Enabled))) - pr_info("KPM: copy_to_user() failed\n"); - return 0; - } - - // Checking hook usage - if (arg2 == CMD_HOOK_TYPE) { - const char *hook_type; - -#if defined(CONFIG_KSU_KPROBES_HOOK) - hook_type = "Kprobes"; -#elif defined(CONFIG_KSU_TRACEPOINT_HOOK) - hook_type = "Tracepoint"; -#elif defined(CONFIG_KSU_MANUAL_HOOK) - hook_type = "Manual"; -#else - hook_type = "Unknown"; -#endif - - size_t len = strlen(hook_type) + 1; - if (copy_to_user((void __user *)arg3, hook_type, len)) { - pr_err("hook_type: copy_to_user failed\n"); - return 0; - } - - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("hook_type: prctl reply error\n"); - } - return 0; - } #ifdef CONFIG_KSU_MANUAL_SU - if (arg2 == CMD_MANUAL_SU_REQUEST) { - struct manual_su_request request; - int su_option = (int)arg3; - - if (copy_from_user(&request, (void __user *)arg4, sizeof(request))) { - pr_err("manual_su: failed to copy request from user\n"); - return 0; - } + if (arg2 == CMD_MANUAL_SU_REQUEST) { + struct manual_su_request request; + int su_option = (int)arg3; + + if (copy_from_user(&request, (void __user *)arg4, sizeof(request))) { + pr_err("manual_su: failed to copy request from user\n"); + return 0; + } - int ret = ksu_handle_manual_su_request(su_option, &request); + int ret = ksu_handle_manual_su_request(su_option, &request); - // Copy back result for token generation - if (ret == 0 && su_option == MANUAL_SU_OP_GENERATE_TOKEN) { - if (copy_to_user((void __user *)arg4, &request, sizeof(request))) { - pr_err("manual_su: failed to copy request back to user\n"); - return 0; - } - } - - if (ret == 0) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("manual_su: prctl reply error\n"); - } - } - return 0; - } + // Copy back result for token generation + if (ret == 0 && su_option == MANUAL_SU_OP_GENERATE_TOKEN) { + if (copy_to_user((void __user *)arg4, &request, sizeof(request))) { + pr_err("manual_su: failed to copy request back to user\n"); + return 0; + } + } + + if (ret == 0) { + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("manual_su: prctl reply error\n"); + } + } + return 0; + } #endif #ifdef CONFIG_KSU_SUSFS - int susfs_cmd_err = 0; + int susfs_cmd_err = 0; #ifdef CONFIG_KSU_SUSFS_SUS_PATH - if (arg2 == CMD_SUSFS_ADD_SUS_PATH) { - susfs_cmd_err = susfs_add_sus_path((struct st_susfs_sus_path __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_ADD_SUS_PATH_LOOP) { - susfs_cmd_err = susfs_add_sus_path_loop((struct st_susfs_sus_path __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH_LOOP -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) { - susfs_cmd_err = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH); - pr_info("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_SET_SDCARD_ROOT_PATH) { - susfs_cmd_err = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_SDCARD_ROOT_PATH); - pr_info("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ADD_SUS_PATH) { + susfs_cmd_err = susfs_add_sus_path((struct st_susfs_sus_path __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_ADD_SUS_PATH_LOOP) { + susfs_cmd_err = susfs_add_sus_path_loop((struct st_susfs_sus_path __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH_LOOP -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) { + susfs_cmd_err = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH); + pr_info("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_SET_SDCARD_ROOT_PATH) { + susfs_cmd_err = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_SDCARD_ROOT_PATH); + pr_info("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_PATH #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (arg2 == CMD_SUSFS_ADD_SUS_MOUNT) { - susfs_cmd_err = susfs_add_sus_mount((struct st_susfs_sus_mount __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) { - if (arg3 != 0 && arg3 != 1) { - pr_err("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> arg3 can only be 0 or 1\n"); - return 0; - } - susfs_hide_sus_mnts_for_all_procs = arg3; - pr_info("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> susfs_hide_sus_mnts_for_all_procs: %lu\n", arg3); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) { - if (arg3 != 0 && arg3 != 1) { - pr_err("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> arg3 can only be 0 or 1\n"); - return 0; - } - susfs_is_umount_for_zygote_iso_service_enabled = arg3; - pr_info("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> susfs_is_umount_for_zygote_iso_service_enabled: %lu\n", arg3); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ADD_SUS_MOUNT) { + susfs_cmd_err = susfs_add_sus_mount((struct st_susfs_sus_mount __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) { + if (arg3 != 0 && arg3 != 1) { + pr_err("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> arg3 can only be 0 or 1\n"); + return 0; + } + susfs_hide_sus_mnts_for_all_procs = arg3; + pr_info("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> susfs_hide_sus_mnts_for_all_procs: %lu\n", arg3); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) { + if (arg3 != 0 && arg3 != 1) { + pr_err("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> arg3 can only be 0 or 1\n"); + return 0; + } + susfs_is_umount_for_zygote_iso_service_enabled = arg3; + pr_info("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> susfs_is_umount_for_zygote_iso_service_enabled: %lu\n", arg3); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT #ifdef CONFIG_KSU_SUSFS_SUS_KSTAT - if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT) { - susfs_cmd_err = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_UPDATE_SUS_KSTAT) { - susfs_cmd_err = susfs_update_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); - pr_info("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) { - susfs_cmd_err = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT) { + susfs_cmd_err = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_UPDATE_SUS_KSTAT) { + susfs_cmd_err = susfs_update_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); + pr_info("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) { + susfs_cmd_err = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT - if (arg2 == CMD_SUSFS_ADD_TRY_UMOUNT) { - susfs_cmd_err = susfs_add_try_umount((struct st_susfs_try_umount __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ADD_TRY_UMOUNT) { + susfs_cmd_err = susfs_add_try_umount((struct st_susfs_try_umount __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT #ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME - if (arg2 == CMD_SUSFS_SET_UNAME) { - susfs_cmd_err = susfs_set_uname((struct st_susfs_uname __user*)arg3); - pr_info("susfs: CMD_SUSFS_SET_UNAME -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_SET_UNAME) { + susfs_cmd_err = susfs_set_uname((struct st_susfs_uname __user*)arg3); + pr_info("susfs: CMD_SUSFS_SET_UNAME -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME #ifdef CONFIG_KSU_SUSFS_ENABLE_LOG - if (arg2 == CMD_SUSFS_ENABLE_LOG) { - if (arg3 != 0 && arg3 != 1) { - pr_err("susfs: CMD_SUSFS_ENABLE_LOG -> arg3 can only be 0 or 1\n"); - return 0; - } - susfs_set_log(arg3); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ENABLE_LOG) { + if (arg3 != 0 && arg3 != 1) { + pr_err("susfs: CMD_SUSFS_ENABLE_LOG -> arg3 can only be 0 or 1\n"); + return 0; + } + susfs_set_log(arg3); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG #ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG - if (arg2 == CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG) { - susfs_cmd_err = susfs_set_cmdline_or_bootconfig((char __user*)arg3); - pr_info("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG) { + susfs_cmd_err = susfs_set_cmdline_or_bootconfig((char __user*)arg3); + pr_info("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG #ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT - if (arg2 == CMD_SUSFS_ADD_OPEN_REDIRECT) { - susfs_cmd_err = susfs_add_open_redirect((struct st_susfs_open_redirect __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ADD_OPEN_REDIRECT) { + susfs_cmd_err = susfs_add_open_redirect((struct st_susfs_open_redirect __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT #ifdef CONFIG_KSU_SUSFS_SUS_SU - if (arg2 == CMD_SUSFS_SUS_SU) { - susfs_cmd_err = susfs_sus_su((struct st_sus_su __user*)arg3); - pr_info("susfs: CMD_SUSFS_SUS_SU -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_SUS_SU) { + susfs_cmd_err = susfs_sus_su((struct st_sus_su __user*)arg3); + pr_info("susfs: CMD_SUSFS_SUS_SU -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS_SUS_SU - if (arg2 == CMD_SUSFS_SHOW_VERSION) { - int len_of_susfs_version = strlen(SUSFS_VERSION); - char *susfs_version = SUSFS_VERSION; + if (arg2 == CMD_SUSFS_SHOW_VERSION) { + int len_of_susfs_version = strlen(SUSFS_VERSION); + char *susfs_version = SUSFS_VERSION; - susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)susfs_version, len_of_susfs_version+1); - pr_info("susfs: CMD_SUSFS_SHOW_VERSION -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_SHOW_ENABLED_FEATURES) { - if (arg4 <= 0) { - pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg4 cannot be <= 0\n"); - return 0; - } - susfs_cmd_err = susfs_get_enabled_features((char __user*)arg3, arg4); - pr_info("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_SHOW_VARIANT) { - int len_of_variant = strlen(SUSFS_VARIANT); - char *susfs_variant = SUSFS_VARIANT; + susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)susfs_version, len_of_susfs_version+1); + pr_info("susfs: CMD_SUSFS_SHOW_VERSION -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_SHOW_ENABLED_FEATURES) { + if (arg4 <= 0) { + pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg4 cannot be <= 0\n"); + return 0; + } + susfs_cmd_err = susfs_get_enabled_features((char __user*)arg3, arg4); + pr_info("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_SHOW_VARIANT) { + int len_of_variant = strlen(SUSFS_VARIANT); + char *susfs_variant = SUSFS_VARIANT; - susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)susfs_variant, len_of_variant+1); - pr_info("susfs: CMD_SUSFS_SHOW_VARIANT -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)susfs_variant, len_of_variant+1); + pr_info("susfs: CMD_SUSFS_SHOW_VARIANT -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #ifdef CONFIG_KSU_SUSFS_SUS_SU - if (arg2 == CMD_SUSFS_IS_SUS_SU_READY) { - susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)&susfs_is_sus_su_ready, sizeof(susfs_is_sus_su_ready)); - pr_info("susfs: CMD_SUSFS_IS_SUS_SU_READY -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) { - int working_mode = susfs_get_sus_su_working_mode(); + if (arg2 == CMD_SUSFS_IS_SUS_SU_READY) { + susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)&susfs_is_sus_su_ready, sizeof(susfs_is_sus_su_ready)); + pr_info("susfs: CMD_SUSFS_IS_SUS_SU_READY -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } + if (arg2 == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) { + int working_mode = susfs_get_sus_su_working_mode(); - susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)&working_mode, sizeof(working_mode)); - pr_info("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + susfs_cmd_err = copy_to_user((void __user*)arg3, (void*)&working_mode, sizeof(working_mode)); + pr_info("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU #ifdef CONFIG_KSU_SUSFS_SUS_MAP - if (arg2 == CMD_SUSFS_ADD_SUS_MAP) { - susfs_cmd_err = susfs_add_sus_map((struct st_susfs_sus_map __user*)arg3); - pr_info("susfs: CMD_SUSFS_ADD_SUS_MAP -> ret: %d\n", susfs_cmd_err); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ADD_SUS_MAP) { + susfs_cmd_err = susfs_add_sus_map((struct st_susfs_sus_map __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_MAP -> ret: %d\n", susfs_cmd_err); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MAP - if (arg2 == CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING) { - if (arg3 != 0 && arg3 != 1) { - pr_err("susfs: CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING -> arg3 can only be 0 or 1\n"); - return 0; - } - susfs_set_avc_log_spoofing(arg3); - if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } + if (arg2 == CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING) { + if (arg3 != 0 && arg3 != 1) { + pr_err("susfs: CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING -> arg3 can only be 0 or 1\n"); + return 0; + } + susfs_set_avc_log_spoofing(arg3); + if (copy_to_user((void __user*)arg5, &susfs_cmd_err, sizeof(susfs_cmd_err))) + pr_info("susfs: copy_to_user() failed\n"); + return 0; + } #endif //#ifdef CONFIG_KSU_SUSFS - // all other cmds are for 'root manager' - if (!from_manager) { - return 0; - } - - // we are already manager - if (arg2 == CMD_GET_APP_PROFILE) { - struct app_profile profile; - if (copy_from_user(&profile, arg3, sizeof(profile))) { - pr_err("copy profile failed\n"); - return 0; - } - - bool success = ksu_get_app_profile(&profile); - if (success) { - if (copy_to_user(arg3, &profile, sizeof(profile))) { - pr_err("copy profile failed\n"); - return 0; - } - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - } - return 0; - } - - if (arg2 == CMD_SET_APP_PROFILE) { - struct app_profile profile; - if (copy_from_user(&profile, arg3, sizeof(profile))) { - pr_err("copy profile failed\n"); - return 0; - } - - // todo: validate the params - if (ksu_set_app_profile(&profile, true)) { -#if __SULOG_GATE - ksu_sulog_report_manager_operation("SET_APP_PROFILE", - current_uid().val, profile.current_uid); -#endif - - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - } - return 0; - } - - if (arg2 == CMD_IS_SU_ENABLED) { - if (copy_to_user(arg3, &ksu_su_compat_enabled, - sizeof(ksu_su_compat_enabled))) { - pr_err("copy su compat failed\n"); - return 0; - } - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - // UID Scanner control command - if (arg2 == CMD_ENABLE_UID_SCANNER) { - if (arg3 == 0) { - // Get current status - bool status = ksu_uid_scanner_enabled; - if (copy_to_user((void __user *)arg4, &status, sizeof(status))) { - pr_err("uid_scanner: copy status failed\n"); - return 0; - } - } else if (arg3 == 1) { - // Enable/Disable toggle - bool enabled = (arg4 != 0); - - if (enabled == ksu_uid_scanner_enabled) { - pr_info("uid_scanner: no need to change, already %s\n", - enabled ? "enabled" : "disabled"); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("uid_scanner: prctl reply error\n"); - } - return 0; - } - - if (enabled) { - // Enable UID scanner - int ret = ksu_throne_comm_init(); - if (ret != 0) { - pr_err("uid_scanner: failed to initialize: %d\n", ret); - return 0; - } - pr_info("uid_scanner: enabled\n"); - } else { - // Disable UID scanner - ksu_throne_comm_exit(); - pr_info("uid_scanner: disabled\n"); - } - - ksu_uid_scanner_enabled = enabled; - ksu_throne_comm_save_state(); - } else if (arg3 == 2) { - // Clear environment (force exit) - ksu_throne_comm_exit(); - ksu_uid_scanner_enabled = false; - ksu_throne_comm_save_state(); - pr_info("uid_scanner: environment cleared\n"); - } - - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("uid_scanner: prctl reply error\n"); - } - return 0; - } #if defined(CONFIG_KSU_SUSFS) && defined(CONFIG_KSU_MANUAL_SU) if (unlikely(saved_umount_flag)) set_ti_thread_flag(¤t->thread_info, TIF_PROC_UMOUNTED); #endif - return 0; + return 0; } static bool is_appuid(kuid_t uid) @@ -1321,66 +852,66 @@ static bool is_appuid(kuid_t uid) #define FIRST_APPLICATION_UID 10000 #define LAST_APPLICATION_UID 19999 - uid_t appid = uid.val % PER_USER_RANGE; - return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; + uid_t appid = uid.val % PER_USER_RANGE; + return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; } static bool should_umount(struct path *path) { - if (!path) { - return false; - } + if (!path) { + return false; + } - if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) { - pr_info("ignore global mnt namespace process: %d\n", - current_uid().val); - return false; - } + if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) { + pr_info("ignore global mnt namespace process: %d\n", + current_uid().val); + return false; + } #ifdef CONFIG_KSU_SUSFS - return susfs_is_mnt_devname_ksu(path); + return susfs_is_mnt_devname_ksu(path); #else - if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) { - const char *fstype = path->mnt->mnt_sb->s_type->name; - return strcmp(fstype, "overlay") == 0; - } - return false; + if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) { + const char *fstype = path->mnt->mnt_sb->s_type->name; + return strcmp(fstype, "overlay") == 0; + } + return false; #endif } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT) static int ksu_path_umount(struct path *path, int flags) { - return path_umount(path, flags); + return path_umount(path, flags); } -#define ksu_umount_mnt(__unused, path, flags) (ksu_path_umount(path, flags)) +#define ksu_umount_mnt(__unused, path, flags) (ksu_path_umount(path, flags)) #else // TODO: Search a way to make this works without set_fs functions static int ksu_sys_umount(const char *mnt, int flags) { - char __user *usermnt = (char __user *)mnt; - mm_segment_t old_fs; - int ret; // although asmlinkage long + char __user *usermnt = (char __user *)mnt; + mm_segment_t old_fs; + int ret; // although asmlinkage long - old_fs = get_fs(); - set_fs(KERNEL_DS); + old_fs = get_fs(); + set_fs(KERNEL_DS); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) - ret = ksys_umount(usermnt, flags); + ret = ksys_umount(usermnt, flags); #else - ret = sys_umount(usermnt, flags); // cuz asmlinkage long sys##name + ret = sys_umount(usermnt, flags); // cuz asmlinkage long sys##name #endif - set_fs(old_fs); - pr_info("%s was called, ret: %d\n", __func__, ret); - return ret; + set_fs(old_fs); + pr_info("%s was called, ret: %d\n", __func__, ret); + return ret; } -#define ksu_umount_mnt(mnt, __unused, flags) \ - ({ \ - int ret; \ - path_put(__unused); \ - ret = ksu_sys_umount(mnt, flags); \ - ret; \ - }) +#define ksu_umount_mnt(mnt, __unused, flags) \ + ({ \ + int ret; \ + path_put(__unused); \ + ret = ksu_sys_umount(mnt, flags); \ + ret; \ + }) #endif @@ -1390,323 +921,364 @@ void try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid) static void try_umount(const char *mnt, bool check_mnt, int flags) #endif { - struct path path; - int ret; - int err = kern_path(mnt, 0, &path); - if (err) { - return; - } + struct path path; + int ret; + 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; + } - // we are only interest in some specific mounts - if (check_mnt && !should_umount(&path)) { - path_put(&path); - return; - } + // we are only interest in some specific mounts + if (check_mnt && !should_umount(&path)) { + 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' for uid: %d\n", mnt, uid); - } + if (susfs_is_log_enabled) { + pr_info("susfs: umounting '%s' for uid: %d\n", mnt, uid); + } #endif - ret = ksu_umount_mnt(mnt, &path, flags); - if (ret) { + ret = ksu_umount_mnt(mnt, &path, flags); + if (ret) { #ifdef CONFIG_KSU_DEBUG - pr_info("%s: path: %s, ret: %d\n", __func__, mnt, ret); + pr_info("%s: path: %s, ret: %d\n", __func__, mnt, ret); #endif - } + } } #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT void susfs_try_umount_all(uid_t uid) { - susfs_try_umount(uid); - /* For Legacy KSU only */ - try_umount("/odm", true, 0, uid); - try_umount("/system", true, 0, uid); - try_umount("/vendor", true, 0, uid); - try_umount("/product", true, 0, uid); - try_umount("/system_ext", true, 0, uid); - // - For '/data/adb/modules' we pass 'false' here because it is a loop device that we can't determine whether - // its dev_name is KSU or not, and it is safe to just umount it if it is really a mountpoint - try_umount("/data/adb/modules", false, MNT_DETACH, uid); - try_umount("/data/adb/kpm", false, MNT_DETACH, uid); - /* For both Legacy KSU and Magic Mount KSU */ - try_umount("/debug_ramdisk", true, MNT_DETACH, uid); - try_umount("/sbin", false, MNT_DETACH, uid); - - // try umount hosts file - try_umount("/system/etc/hosts", false, MNT_DETACH, uid); + susfs_try_umount(uid); + /* For Legacy KSU only */ + try_umount("/odm", true, 0, uid); + try_umount("/system", true, 0, uid); + try_umount("/vendor", true, 0, uid); + try_umount("/product", true, 0, uid); + try_umount("/system_ext", true, 0, uid); + // - For '/data/adb/modules' we pass 'false' here because it is a loop device that we can't determine whether + // its dev_name is KSU or not, and it is safe to just umount it if it is really a mountpoint + try_umount("/data/adb/modules", false, MNT_DETACH, uid); + try_umount("/data/adb/kpm", false, MNT_DETACH, uid); + /* For both Legacy KSU and Magic Mount KSU */ + try_umount("/debug_ramdisk", true, MNT_DETACH, uid); + try_umount("/sbin", false, MNT_DETACH, uid); + + // try umount hosts file + try_umount("/system/etc/hosts", false, MNT_DETACH, uid); - // try umount lsposed dex2oat bins - try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid); - try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid); + // try umount lsposed dex2oat bins + try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid); + try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid); } #endif #ifdef CONFIG_KSU_SUSFS int ksu_handle_setuid(struct cred *new, const struct cred *old) { - // 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 (!new || !old) { + return 0; + } - if (!new || !old) { - return 0; - } + kuid_t new_uid = new->uid; + kuid_t old_uid = old->uid; - kuid_t new_uid = new->uid; - kuid_t old_uid = old->uid; + if (0 != old_uid.val) { + // old process is not root, ignore it. + return 0; + } - if (0 != old_uid.val) { - // old process is not root, ignore it. - return 0; - } + if (ksu_get_manager_uid() == new_uid.val) { + pr_info("install fd for: %d\n", new_uid.val); - // We only interest in process spwaned by zygote - if (!susfs_is_sid_equal(old->security, susfs_zygote_sid)) { - return 0; - } + ksu_install_fd(); + spin_lock_irq(¤t->sighand->siglock); + ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + return 0; + } - // Check if spawned process is isolated service first, and force to do umount if so - if (is_zygote_isolated_service_uid(new_uid.val) && susfs_is_umount_for_zygote_iso_service_enabled) { - goto do_umount; - } + if (ksu_is_allow_uid(new_uid.val)) { + if (current->seccomp.mode == SECCOMP_MODE_FILTER && + current->seccomp.filter) { + spin_lock_irq(¤t->sighand->siglock); + ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + } + } - // - 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.val belongs to - // ksu manager - if (ksu_is_manager_uid_valid() && - (new_uid.val % 1000000 == ksu_get_manager_uid())) // % 1000000 in case it is private space uid - { - 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; + } - // Check if spawned process is normal user app and needs to be umounted - if (likely(is_zygote_normal_app_uid(new_uid.val) && ksu_uid_should_umount(new_uid.val))) { - goto do_umount; - } + // We only interest in process spwaned by zygote + if (!susfs_is_sid_equal(old->security, susfs_zygote_sid)) { + return 0; + } - // Lastly, Check if spawned process is some system process and needs to be umounted - if (unlikely(is_some_system_uid(new_uid.val) && susfs_is_umount_for_zygote_system_process_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.val) && susfs_is_umount_for_zygote_iso_service_enabled) { + goto do_umount; + } + + // - 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.val belongs to + // ksu manager + if (ksu_is_manager_uid_valid() && + (new_uid.val % 1000000 == ksu_get_manager_uid())) // % 1000000 in case it is private space uid + { + return 0; + } + + // Check if spawned process is normal user app and needs to be umounted + if (likely(is_zygote_normal_app_uid(new_uid.val) && ksu_uid_should_umount(new_uid.val))) { + 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.val) && susfs_is_umount_for_zygote_system_process_enabled)) { + goto do_umount; + } #if __SULOG_GATE - ksu_sulog_report_syscall(new_uid.val, NULL, "setuid", NULL); + ksu_sulog_report_syscall(new_uid.val, NULL, "setuid", NULL); #endif - return 0; + return 0; do_umount: #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT - // susfs come first, and lastly umount by ksu, make sure umount in reversed order - susfs_try_umount_all(new_uid.val); + // susfs come first, and lastly umount by ksu, make sure umount in reversed order + susfs_try_umount_all(new_uid.val); #else - // fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and - // filter the mountpoint whose target is `/data/adb` - try_umount("/odm", true, 0); - try_umount("/system", true, 0); - try_umount("/vendor", true, 0); - try_umount("/product", true, 0); - try_umount("/system_ext", true, 0); - try_umount("/data/adb/modules", false, MNT_DETACH); + // fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and + // filter the mountpoint whose target is `/data/adb` + try_umount("/odm", true, 0); + try_umount("/system", true, 0); + try_umount("/vendor", true, 0); + try_umount("/product", true, 0); + try_umount("/system_ext", true, 0); + try_umount("/data/adb/modules", false, MNT_DETACH); - // try umount ksu temp path - try_umount("/debug_ramdisk", false, MNT_DETACH); + // try umount ksu temp path + try_umount("/debug_ramdisk", false, MNT_DETACH); - try_umount("/sbin", false, MNT_DETACH, uid); - - // try umount hosts file - try_umount("/system/etc/hosts", false, MNT_DETACH, uid); + try_umount("/sbin", false, MNT_DETACH, uid); + + // try umount hosts file + try_umount("/system/etc/hosts", false, MNT_DETACH, uid); - // try umount lsposed dex2oat bins - try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid); - try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid); + // try umount lsposed dex2oat bins + try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid); + try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid); #endif // #ifdef CONFIG_KSU_SUSFS_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.val); + susfs_run_sus_path_loop(new_uid.val); #endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH - return 0; + return 0; } #else int ksu_handle_setuid(struct cred *new, const struct cred *old) { - // 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 (!new || !old) { + return 0; + } - if (!new || !old) { - return 0; - } + kuid_t new_uid = new->uid; + kuid_t old_uid = old->uid; - kuid_t new_uid = new->uid; - kuid_t old_uid = old->uid; + if (0 != old_uid.val) { + // old process is not root, ignore it. + return 0; + } - if (0 != old_uid.val) { - // old process is not root, ignore it. - return 0; - } + if (!is_appuid(new_uid) || is_unsupported_uid(new_uid.val)) { + // pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val); + return 0; + } - if (!is_appuid(new_uid) || is_unsupported_uid(new_uid.val)) { - // pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val); - return 0; - } + if (ksu_get_manager_uid() == new_uid.val) { + pr_info("install fd for: %d\n", new_uid.val); - if (ksu_is_allow_uid(new_uid.val)) { - // pr_info("handle setuid ignore allowed application: %d\n", new_uid.val); - return 0; - } + ksu_install_fd(); + spin_lock_irq(¤t->sighand->siglock); + ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + return 0; + } - if (!ksu_uid_should_umount(new_uid.val)) { - return 0; - } else { + if (ksu_is_allow_uid(new_uid.val)) { + if (current->seccomp.mode == SECCOMP_MODE_FILTER && + current->seccomp.filter) { + spin_lock_irq(¤t->sighand->siglock); + ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + spin_unlock_irq(¤t->sighand->siglock); + } + } + + // 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_uid_should_umount(new_uid.val)) { + return 0; + } else { #ifdef CONFIG_KSU_DEBUG - pr_info("uid: %d should not umount!\n", current_uid().val); + pr_info("uid: %d should not umount!\n", current_uid().val); #endif - } + } - // 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(old->security); - 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(old->security); + 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.val, NULL, "setuid", NULL); + ksu_sulog_report_syscall(new_uid.val, NULL, "setuid", NULL); #endif #ifdef CONFIG_KSU_DEBUG - // umount the target mnt - pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, - current->pid); + // umount the target mnt + pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, + current->pid); #endif - // fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and - // filter the mountpoint whose target is `/data/adb` - try_umount("/odm", true, 0); - try_umount("/system", true, 0); - try_umount("/vendor", true, 0); - try_umount("/product", true, 0); - try_umount("/system_ext", true, 0); - try_umount("/data/adb/modules", false, MNT_DETACH); + // fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and + // filter the mountpoint whose target is `/data/adb` + try_umount("/odm", true, 0); + try_umount("/system", true, 0); + try_umount("/vendor", true, 0); + try_umount("/product", true, 0); + try_umount("/system_ext", true, 0); + try_umount("/data/adb/modules", false, MNT_DETACH); - // try umount ksu temp path - try_umount("/debug_ramdisk", false, MNT_DETACH); - - // try umount ksu su path - try_umount("/sbin", false, MNT_DETACH); + // try umount ksu temp path + try_umount("/debug_ramdisk", false, MNT_DETACH); + + // try umount ksu su path + try_umount("/sbin", false, MNT_DETACH); - return 0; + return 0; } #endif // #ifdef CONFIG_KSU_SUSFS -static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) +// Init functons - kprobe hooks + +// 1. Reboot hook for installing fd +static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs) { - ksu_handle_prctl(option, arg2, arg3, arg4, arg5); - return -ENOSYS; + 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); + unsigned long arg4; + + // Check if this is a request to install KSU fd + if (magic1 == KSU_INSTALL_MAGIC1 && magic2 == KSU_INSTALL_MAGIC2) { + int fd = ksu_install_fd(); + pr_info("[%d] install ksu fd: %d\n", current->pid, fd); + + arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs); + if (copy_to_user((int *)arg4, &fd, sizeof(fd))) { + pr_err("install ksu fd reply err\n"); + } + } + + return 0; +} + +static struct kprobe reboot_kp = { + .symbol_name = REBOOT_SYMBOL, + .pre_handler = reboot_handler_pre, +}; + +static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + ksu_handle_prctl(option, arg2, arg3, arg4, arg5); + return -ENOSYS; } // 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 -#ifndef DEVPTS_SUPER_MAGIC -#define DEVPTS_SUPER_MAGIC 0x1cd1 -#endif - -extern int __ksu_handle_devpts(struct inode *inode); // sucompat.c - int ksu_inode_permission(struct inode *inode, int mask) { - if (inode && inode->i_sb - && unlikely(inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)) { - //pr_info("%s: handling devpts for: %s \n", __func__, current->comm); - __ksu_handle_devpts(inode); - } - return 0; + if (inode && inode->i_sb + && unlikely(inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)) { + //pr_info("%s: handling devpts for: %s \n", __func__, current->comm); + __ksu_handle_devpts(inode); + } + return 0; } -#ifdef CONFIG_KSU_MANUAL_SU -static 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); -} -#endif - -#ifdef CONFIG_COMPAT -bool ksu_is_compat __read_mostly = false; -#endif - int ksu_bprm_check(struct linux_binprm *bprm) { - char *filename = (char *)bprm->filename; - - if (likely(!ksu_execveat_hook)) - return 0; + char *filename = (char *)bprm->filename; + + if (likely(!ksu_execveat_hook)) + return 0; #ifdef CONFIG_COMPAT - static bool compat_check_done __read_mostly = false; - if ( unlikely(!compat_check_done) && unlikely(!strcmp(filename, "/data/adb/ksud")) - && !memcmp(bprm->buf, "\x7f\x45\x4c\x46", 4) ) { - if (bprm->buf[4] == 0x01 ) - ksu_is_compat = true; + static bool compat_check_done __read_mostly = false; + if ( unlikely(!compat_check_done) && unlikely(!strcmp(filename, "/data/adb/ksud")) + && !memcmp(bprm->buf, "\x7f\x45\x4c\x46", 4) ) { + if (bprm->buf[4] == 0x01 ) + ksu_is_compat = true; - pr_info("%s: %s ELF magic found! ksu_is_compat: %d \n", __func__, filename, ksu_is_compat); - compat_check_done = true; - } + pr_info("%s: %s ELF magic found! ksu_is_compat: %d \n", __func__, filename, ksu_is_compat); + compat_check_done = true; + } #endif - ksu_handle_pre_ksud(filename); + ksu_handle_pre_ksud(filename); #ifdef CONFIG_KSU_MANUAL_SU - ksu_try_escalate_for_uid(current_uid().val); + ksu_try_escalate_for_uid(current_uid().val); #endif - return 0; + return 0; } @@ -1714,266 +1286,265 @@ int ksu_bprm_check(struct linux_binprm *bprm) static int ksu_task_alloc(struct task_struct *task, 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 -static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) -{ - return ksu_handle_rename(old_dentry, new_dentry); -} - static int ksu_task_fix_setuid(struct cred *new, const struct cred *old, - int flags) + int flags) { - return ksu_handle_setuid(new, old); + return ksu_handle_setuid(new, old); } #ifndef MODULE static struct security_hook_list ksu_hooks[] = { - LSM_HOOK_INIT(task_prctl, ksu_task_prctl), - LSM_HOOK_INIT(inode_rename, ksu_inode_rename), - LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid), - LSM_HOOK_INIT(inode_permission, ksu_inode_permission), + LSM_HOOK_INIT(task_prctl, ksu_task_prctl), + LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid), + LSM_HOOK_INIT(inode_permission, ksu_inode_permission), #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0) && defined(CONFIG_KSU_MANUAL_SU) LSM_HOOK_INIT(task_alloc, ksu_task_alloc), #endif #ifndef CONFIG_KSU_KPROBES_HOOK - LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check), + LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check), #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 } #else -// keep renameat_handler for LKM support -static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) - // https://elixir.bootlin.com/linux/v5.12-rc1/source/include/linux/fs.h - struct renamedata *rd = PT_REGS_PARM1(regs); - struct dentry *old_entry = rd->old_dentry; - struct dentry *new_entry = rd->new_dentry; -#else - struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs); - struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs); -#endif - - return ksu_handle_rename(old_entry, new_entry); -} - -static struct kprobe renameat_kp = { - .symbol_name = "vfs_rename", - .pre_handler = renameat_handler_pre, -}; static int override_security_head(void *head, const void *new_head, size_t len) { - unsigned long base = (unsigned long)head & PAGE_MASK; - unsigned long offset = offset_in_page(head); + unsigned long base = (unsigned long)head & PAGE_MASK; + unsigned long offset = offset_in_page(head); - // this is impossible for our case because the page alignment - // but be careful for other cases! - BUG_ON(offset + len > PAGE_SIZE); - struct page *page = phys_to_page(__pa(base)); - if (!page) { - return -EFAULT; - } + // this is impossible for our case because the page alignment + // but be careful for other cases! + BUG_ON(offset + len > PAGE_SIZE); + struct page *page = phys_to_page(__pa(base)); + if (!page) { + return -EFAULT; + } - void *addr = vmap(&page, 1, VM_MAP, PAGE_KERNEL); - if (!addr) { - return -ENOMEM; - } - local_irq_disable(); - memcpy(addr + offset, new_head, len); - local_irq_enable(); - vunmap(addr); - return 0; + void *addr = vmap(&page, 1, VM_MAP, PAGE_KERNEL); + if (!addr) { + return -ENOMEM; + } + local_irq_disable(); + memcpy(addr + offset, new_head, len); + local_irq_enable(); + vunmap(addr); + return 0; } static void free_security_hook_list(struct hlist_head *head) { - struct hlist_node *temp; - struct security_hook_list *entry; + struct hlist_node *temp; + struct security_hook_list *entry; - if (!head) - return; + if (!head) + return; - hlist_for_each_entry_safe (entry, temp, head, list) { - hlist_del(&entry->list); - kfree(entry); - } + hlist_for_each_entry_safe (entry, temp, head, list) { + hlist_del(&entry->list); + kfree(entry); + } - kfree(head); + kfree(head); } struct hlist_head *copy_security_hlist(struct hlist_head *orig) { - struct hlist_head *new_head = kmalloc(sizeof(*new_head), GFP_KERNEL); - if (!new_head) - return NULL; + struct hlist_head *new_head = kmalloc(sizeof(*new_head), GFP_KERNEL); + if (!new_head) + return NULL; - INIT_HLIST_HEAD(new_head); + INIT_HLIST_HEAD(new_head); - struct security_hook_list *entry; - struct security_hook_list *new_entry; + struct security_hook_list *entry; + struct security_hook_list *new_entry; - hlist_for_each_entry (entry, orig, list) { - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); - if (!new_entry) { - free_security_hook_list(new_head); - return NULL; - } + hlist_for_each_entry (entry, orig, list) { + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + if (!new_entry) { + free_security_hook_list(new_head); + return NULL; + } - *new_entry = *entry; + *new_entry = *entry; - hlist_add_tail_rcu(&new_entry->list, new_head); - } + hlist_add_tail_rcu(&new_entry->list, new_head); + } - return new_head; + return new_head; } #define LSM_SEARCH_MAX 180 // This should be enough to iterate static void *find_head_addr(void *security_ptr, int *index) { - if (!security_ptr) { - return NULL; - } - struct hlist_head *head_start = - (struct hlist_head *)&security_hook_heads; + if (!security_ptr) { + return NULL; + } + struct hlist_head *head_start = + (struct hlist_head *)&security_hook_heads; - for (int i = 0; i < LSM_SEARCH_MAX; i++) { - struct hlist_head *head = head_start + i; - struct security_hook_list *pos; - hlist_for_each_entry (pos, head, list) { - if (pos->hook.capget == security_ptr) { - if (index) { - *index = i; - } - return head; - } - } - } + for (int i = 0; i < LSM_SEARCH_MAX; i++) { + struct hlist_head *head = head_start + i; + struct security_hook_list *pos; + hlist_for_each_entry (pos, head, list) { + if (pos->hook.capget == security_ptr) { + if (index) { + *index = i; + } + return head; + } + } + } - return NULL; + return NULL; } #define GET_SYMBOL_ADDR(sym) \ - ({ \ - void *addr = kallsyms_lookup_name(#sym ".cfi_jt"); \ - if (!addr) { \ - addr = kallsyms_lookup_name(#sym); \ - } \ - addr; \ - }) + ({ \ + void *addr = kallsyms_lookup_name(#sym ".cfi_jt"); \ + if (!addr) { \ + addr = kallsyms_lookup_name(#sym); \ + } \ + addr; \ + }) #define KSU_LSM_HOOK_HACK_INIT(head_ptr, name, func) \ - do { \ - static struct security_hook_list hook = { \ - .hook = { .name = func } \ - }; \ - hook.head = head_ptr; \ - hook.lsm = "ksu"; \ - struct hlist_head *new_head = copy_security_hlist(hook.head); \ - if (!new_head) { \ - pr_err("Failed to copy security list: %s\n", #name); \ - break; \ - } \ - hlist_add_tail_rcu(&hook.list, new_head); \ - if (override_security_head(hook.head, new_head, \ - sizeof(*new_head))) { \ - free_security_hook_list(new_head); \ - pr_err("Failed to hack lsm for: %s\n", #name); \ - } \ - } while (0) + do { \ + static struct security_hook_list hook = { \ + .hook = { .name = func } \ + }; \ + hook.head = head_ptr; \ + hook.lsm = "ksu"; \ + struct hlist_head *new_head = copy_security_hlist(hook.head); \ + if (!new_head) { \ + pr_err("Failed to copy security list: %s\n", #name); \ + break; \ + } \ + hlist_add_tail_rcu(&hook.list, new_head); \ + if (override_security_head(hook.head, new_head, \ + sizeof(*new_head))) { \ + free_security_hook_list(new_head); \ + pr_err("Failed to hack lsm for: %s\n", #name); \ + } \ + } while (0) void __init ksu_lsm_hook_init(void) { - void *cap_prctl = GET_SYMBOL_ADDR(cap_task_prctl); - void *prctl_head = find_head_addr(cap_prctl, NULL); - if (prctl_head) { - if (prctl_head != &security_hook_heads.task_prctl) { - pr_warn("prctl's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(prctl_head, task_prctl, ksu_task_prctl); - } else { - pr_warn("Failed to find task_prctl!\n"); - } + void *cap_prctl = GET_SYMBOL_ADDR(cap_task_prctl); + void *prctl_head = find_head_addr(cap_prctl, NULL); + if (prctl_head) { + if (prctl_head != &security_hook_heads.task_prctl) { + pr_warn("prctl's address has shifted!\n"); + } + KSU_LSM_HOOK_HACK_INIT(prctl_head, task_prctl, ksu_task_prctl); + } else { + pr_warn("Failed to find task_prctl!\n"); + } - int inode_killpriv_index = -1; - void *cap_killpriv = GET_SYMBOL_ADDR(cap_inode_killpriv); - find_head_addr(cap_killpriv, &inode_killpriv_index); - if (inode_killpriv_index < 0) { - pr_warn("Failed to find inode_rename, use kprobe instead!\n"); - register_kprobe(&renameat_kp); - } else { - int inode_rename_index = inode_killpriv_index + - &security_hook_heads.inode_rename - - &security_hook_heads.inode_killpriv; - struct hlist_head *head_start = - (struct hlist_head *)&security_hook_heads; - void *inode_rename_head = head_start + inode_rename_index; - if (inode_rename_head != &security_hook_heads.inode_rename) { - pr_warn("inode_rename's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(inode_rename_head, inode_rename, - ksu_inode_rename); - } - void *cap_setuid = GET_SYMBOL_ADDR(cap_task_fix_setuid); - void *setuid_head = find_head_addr(cap_setuid, NULL); - if (setuid_head) { - if (setuid_head != &security_hook_heads.task_fix_setuid) { - pr_warn("setuid's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(setuid_head, task_fix_setuid, - ksu_task_fix_setuid); - } else { - pr_warn("Failed to find task_fix_setuid!\n"); - } - smp_mb(); + int inode_killpriv_index = -1; + void *cap_killpriv = GET_SYMBOL_ADDR(cap_inode_killpriv); + find_head_addr(cap_killpriv, &inode_killpriv_index); + if (inode_killpriv_index < 0) { + pr_warn("Failed to find inode_rename, use kprobe instead!\n"); + register_kprobe(&renameat_kp); + } else { + int inode_rename_index = inode_killpriv_index + + &security_hook_heads.inode_rename - + &security_hook_heads.inode_killpriv; + struct hlist_head *head_start = + (struct hlist_head *)&security_hook_heads; + void *inode_rename_head = head_start + inode_rename_index; + if (inode_rename_head != &security_hook_heads.inode_rename) { + pr_warn("inode_rename's address has shifted!\n"); + } + KSU_LSM_HOOK_HACK_INIT(inode_rename_head, inode_rename, + ksu_inode_rename); + } + void *cap_setuid = GET_SYMBOL_ADDR(cap_task_fix_setuid); + void *setuid_head = find_head_addr(cap_setuid, NULL); + if (setuid_head) { + if (setuid_head != &security_hook_heads.task_fix_setuid) { + pr_warn("setuid's address has shifted!\n"); + } + KSU_LSM_HOOK_HACK_INIT(setuid_head, task_fix_setuid, + ksu_task_fix_setuid); + } else { + pr_warn("Failed to find task_fix_setuid!\n"); + } + smp_mb(); } #endif +__maybe_unused int ksu_kprobe_init(void) +{ + int rc = 0; + + // Register reboot kprobe + rc = register_kprobe(&reboot_kp); + if (rc) { + pr_err("reboot kprobe failed: %d\n", rc); + } else { + pr_info("reboot kprobe registered successfully\n"); + } + + return 0; +} + +__maybe_unused int ksu_kprobe_exit(void) +{ + unregister_kprobe(&reboot_kp); + return 0; +} + void __init ksu_core_init(void) { - ksu_lsm_hook_init(); + ksu_lsm_hook_init(); +#ifdef CONFIG_KPROBES + int rc = ksu_kprobe_init(); + if (rc) { + pr_err("ksu_kprobe_init failed: %d\n", rc); + } +#endif } void ksu_core_exit(void) { - ksu_uid_exit(); - ksu_throne_comm_exit(); + ksu_uid_exit(); + ksu_throne_comm_exit(); #if __SULOG_GATE - ksu_sulog_exit(); + ksu_sulog_exit(); #endif - -#ifdef CONFIG_KSU_KPROBES_HOOK - pr_info("ksu_core_kprobe_exit\n"); - // we dont use this now - // ksu_kprobe_exit(); + +#ifdef CONFIG_KPROBES + pr_info("ksu_core_kprobe_exit\n"); + ksu_kprobe_exit(); #endif } diff --git a/kernel/include/ksu_hook.h b/kernel/include/ksu_hook.h index ea0b04d3..fb0eebc8 100644 --- a/kernel/include/ksu_hook.h +++ b/kernel/include/ksu_hook.h @@ -7,22 +7,22 @@ // For sucompat int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *flags); + int *flags); int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); // For ksud 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); // For ksud and sucompat int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags); + void *envp, int *flags); // For volume button int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, - int *value); + int *value); #endif diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c index 6fe6938b..bf1c974f 100644 --- a/kernel/kernel_compat.c +++ b/kernel/kernel_compat.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) #include #else @@ -10,9 +12,9 @@ #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" // Add check Huawei Device -#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) #include #include #include @@ -20,20 +22,20 @@ struct key *init_session_keyring = NULL; static inline int install_session_keyring(struct key *keyring) { - struct cred *new; - int ret; + struct cred *new; + int ret; - new = prepare_creds(); - if (!new) - return -ENOMEM; + new = prepare_creds(); + if (!new) + return -ENOMEM; - ret = install_session_keyring_to_cred(new, keyring); - if (ret < 0) { - abort_creds(new); - return ret; - } + ret = install_session_keyring_to_cred(new, keyring); + if (ret < 0) { + abort_creds(new); + return ret; + } - return commit_creds(new); + return commit_creds(new); } #endif @@ -41,20 +43,20 @@ extern struct task_struct init_task; // mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA struct ksu_ns_fs_saved { - struct nsproxy *ns; - struct fs_struct *fs; + struct nsproxy *ns; + struct fs_struct *fs; }; static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved) { - ns_fs_saved->ns = current->nsproxy; - ns_fs_saved->fs = current->fs; + ns_fs_saved->ns = current->nsproxy; + ns_fs_saved->fs = current->fs; } static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved) { - current->nsproxy = ns_fs_saved->ns; - current->fs = ns_fs_saved->fs; + current->nsproxy = ns_fs_saved->ns; + current->fs = ns_fs_saved->fs; } static bool android_context_saved_checked = false; @@ -63,178 +65,234 @@ static struct ksu_ns_fs_saved android_context_saved; void ksu_android_ns_fs_check(void) { - if (android_context_saved_checked) - return; - android_context_saved_checked = true; - task_lock(current); - if (current->nsproxy && current->fs && - current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) { - android_context_saved_enabled = true; + if (android_context_saved_checked) + return; + android_context_saved_checked = true; + task_lock(current); + if (current->nsproxy && current->fs && + current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) { + android_context_saved_enabled = true; #ifdef CONFIG_KSU_DEBUG - pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n", - current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns); + pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n", + current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns); #endif - ksu_save_ns_fs(&android_context_saved); - } else { - pr_info("android context saved disabled\n"); - } - task_unlock(current); + ksu_save_ns_fs(&android_context_saved); + } else { + pr_info("android context saved disabled\n"); + } + task_unlock(current); } struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) { -#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)) { - pr_info("installing init session keyring for older kernel\n"); - install_session_keyring(init_session_keyring); - } +#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)) { + pr_info("installing init session keyring for older kernel\n"); + install_session_keyring(init_session_keyring); + } #endif - // switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns - struct ksu_ns_fs_saved saved; - if (android_context_saved_enabled) { + // switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns + struct ksu_ns_fs_saved saved; + if (android_context_saved_enabled) { #ifdef CONFIG_KSU_DEBUG - pr_info("start switch current nsproxy and fs to android context\n"); + pr_info("start switch current nsproxy and fs to android context\n"); #endif - task_lock(current); - ksu_save_ns_fs(&saved); - ksu_load_ns_fs(&android_context_saved); - task_unlock(current); - } - struct file *fp = filp_open(filename, flags, mode); - if (android_context_saved_enabled) { - task_lock(current); - ksu_load_ns_fs(&saved); - task_unlock(current); + task_lock(current); + ksu_save_ns_fs(&saved); + ksu_load_ns_fs(&android_context_saved); + task_unlock(current); + } + struct file *fp = filp_open(filename, flags, mode); + if (android_context_saved_enabled) { + task_lock(current); + ksu_load_ns_fs(&saved); + task_unlock(current); #ifdef CONFIG_KSU_DEBUG - pr_info("switch current nsproxy and fs back to saved successfully\n"); + pr_info("switch current nsproxy and fs back to saved successfully\n"); #endif - } - return fp; + } + return fp; } 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) || defined(KSU_OPTIONAL_KERNEL_READ) - return kernel_read(p, buf, count, pos); + return kernel_read(p, buf, count, pos); #else - loff_t offset = pos ? *pos : 0; - ssize_t result = kernel_read(p, offset, (char *)buf, count); - if (pos && result > 0) { - *pos = offset + result; - } - return result; + loff_t offset = pos ? *pos : 0; + ssize_t result = kernel_read(p, offset, (char *)buf, count); + if (pos && result > 0) { + *pos = offset + result; + } + return result; #endif } ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, - loff_t *pos) + loff_t *pos) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || defined(KSU_OPTIONAL_KERNEL_WRITE) - return kernel_write(p, buf, count, pos); + return kernel_write(p, buf, count, pos); #else - loff_t offset = pos ? *pos : 0; - ssize_t result = kernel_write(p, buf, count, offset); - if (pos && result > 0) { - *pos = offset + result; - } - return result; + loff_t offset = pos ? *pos : 0; + ssize_t result = kernel_write(p, buf, count, offset); + if (pos && result > 0) { + *pos = offset + result; + } + return result; #endif } #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) + long count) { - return strncpy_from_user_nofault(dst, unsafe_addr, count); + return strncpy_from_user_nofault(dst, unsafe_addr, count); } #elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) + long count) { - return strncpy_from_unsafe_user(dst, unsafe_addr, count); + return strncpy_from_unsafe_user(dst, unsafe_addr, count); } #else // Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201 long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) + long count) { - mm_segment_t old_fs = get_fs(); - long ret; + mm_segment_t old_fs = get_fs(); + long ret; - if (unlikely(count <= 0)) - return 0; + if (unlikely(count <= 0)) + return 0; - set_fs(USER_DS); - pagefault_disable(); - ret = strncpy_from_user(dst, unsafe_addr, count); - pagefault_enable(); - set_fs(old_fs); + set_fs(USER_DS); + pagefault_disable(); + ret = strncpy_from_user(dst, unsafe_addr, count); + pagefault_enable(); + set_fs(old_fs); - if (ret >= count) { - ret = count; - dst[ret - 1] = '\0'; - } else if (ret > 0) { - ret++; - } + if (ret >= count) { + ret = count; + dst[ret - 1] = '\0'; + } else if (ret > 0) { + ret++; + } - return ret; + return ret; } #endif long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr, - long count) + long count) { - long ret; + long ret; - ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count); - if (likely(ret >= 0)) - return ret; + ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count); + if (likely(ret >= 0)) + return ret; - // we faulted! fallback to slow path - if (unlikely(!ksu_access_ok(unsafe_addr, count))) { + // we faulted! fallback to slow path + if (unlikely(!ksu_access_ok(unsafe_addr, count))) { #ifdef CONFIG_KSU_DEBUG - pr_err("%s: faulted!\n", __func__); + pr_err("%s: faulted!\n", __func__); #endif - return -EFAULT; - } + return -EFAULT; + } - // why we don't do like how strncpy_from_user_nofault? - ret = strncpy_from_user(dst, unsafe_addr, count); + // why we don't do like how strncpy_from_user_nofault? + ret = strncpy_from_user(dst, unsafe_addr, count); - if (ret >= count) { - ret = count; - dst[ret - 1] = '\0'; - } else if (likely(ret >= 0)) { - ret++; - } + if (ret >= count) { + ret = count; + dst[ret - 1] = '\0'; + } else if (likely(ret >= 0)) { + ret++; + } - return ret; + return ret; } long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) - return copy_from_user_nofault(dst, src, size); + return copy_from_user_nofault(dst, src, size); #else - // https://elixir.bootlin.com/linux/v5.8/source/mm/maccess.c#L205 - long ret = -EFAULT; - mm_segment_t old_fs = get_fs(); + // https://elixir.bootlin.com/linux/v5.8/source/mm/maccess.c#L205 + long ret = -EFAULT; + mm_segment_t old_fs = get_fs(); - set_fs(USER_DS); - // tweaked to use ksu_access_ok - if (ksu_access_ok(src, size)) { - pagefault_disable(); - ret = __copy_from_user_inatomic(dst, src, size); - pagefault_enable(); - } - set_fs(old_fs); + set_fs(USER_DS); + // tweaked to use ksu_access_ok + if (ksu_access_ok(src, size)) { + pagefault_disable(); + ret = __copy_from_user_inatomic(dst, src, size); + pagefault_enable(); + } + set_fs(old_fs); - if (ret) - return -EFAULT; - return 0; + if (ret) + return -EFAULT; + return 0; +#endif +} + +struct action_cache { + DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR); +#ifdef SECCOMP_ARCH_COMPAT + DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR); +#endif +}; + +struct seccomp_filter { + refcount_t refs; + refcount_t users; + bool log; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) + bool wait_killable_recv; +#endif + struct action_cache cache; + struct seccomp_filter *prev; + struct bpf_prog *prog; + struct notification *notif; + struct mutex notify_lock; + wait_queue_head_t wqh; +}; + +void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr) +{ + if (!filter) { + return; + } + + if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) { + clear_bit(nr, filter->cache.allow_native); + } + +#ifdef SECCOMP_ARCH_COMPAT + if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { + clear_bit(nr, filter->cache.allow_compat); + } +#endif +} + +void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr) +{ + if (!filter) { + return; + } + + if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) { + set_bit(nr, filter->cache.allow_native); + } + +#ifdef SECCOMP_ARCH_COMPAT + if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { + set_bit(nr, filter->cache.allow_compat); + } #endif } \ No newline at end of file diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index 22ef54ec..9740ee1b 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -29,9 +29,9 @@ * 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)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 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 #endif @@ -45,25 +45,25 @@ #endif extern long ksu_strncpy_from_user_nofault(char *dst, - const void __user *unsafe_addr, - long count); + const void __user *unsafe_addr, + long count); extern long ksu_strncpy_from_user_retry(char *dst, - const void __user *unsafe_addr, - long count); + const void __user *unsafe_addr, + long count); -#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) extern struct key *init_session_keyring; #endif extern void ksu_android_ns_fs_check(void); extern struct file *ksu_filp_open_compat(const char *filename, int flags, - umode_t mode); + 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); extern long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size); /* * ksu_copy_from_user_retry @@ -72,20 +72,23 @@ extern long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t * 0 = success */ static long ksu_copy_from_user_retry(void *to, - const void __user *from, unsigned long count) + const void __user *from, unsigned long count) { - long ret = ksu_copy_from_user_nofault(to, from, count); - if (likely(!ret)) - return ret; + long ret = ksu_copy_from_user_nofault(to, from, count); + if (likely(!ret)) + return ret; - // we faulted! fallback to slow path - return copy_from_user(to, from, count); + // we faulted! fallback to slow path + return copy_from_user(to, from, count); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) -#define ksu_access_ok(addr, size) access_ok(addr, size) +#define ksu_access_ok(addr, size) access_ok(addr, size) #else -#define ksu_access_ok(addr, size) access_ok(VERIFY_READ, addr, size) +#define ksu_access_ok(addr, size) access_ok(VERIFY_READ, addr, size) #endif +extern void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr); +extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr); + #endif diff --git a/kernel/ksu.c b/kernel/ksu.c index 16230d30..34b1e6d5 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -23,9 +23,9 @@ unsigned int enable_kernelsu = 1; // enabled by default static int __init read_kernelsu_state(char *s) { - if (s) - enable_kernelsu = simple_strtoul(s, NULL, 0); - return 1; + if (s) + enable_kernelsu = simple_strtoul(s, NULL, 0); + return 1; } __setup("kernelsu.enabled=", read_kernelsu_state); @@ -38,21 +38,21 @@ static struct workqueue_struct *ksu_workqueue; bool ksu_queue_work(struct work_struct *work) { - return queue_work(ksu_workqueue, work); + return queue_work(ksu_workqueue, work); } extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags); + void *argv, void *envp, int *flags); extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags); + void *argv, void *envp, int *flags); int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags) + void *envp, int *flags) { - ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags); - return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, - flags); + ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags); + return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, + flags); } extern void ksu_sucompat_init(void); @@ -66,44 +66,44 @@ extern void ksu_trace_unregister(); int __init kernelsu_init(void) { - pr_info("kernelsu.enabled=%d\n", - (int)get_ksu_state()); + pr_info("kernelsu.enabled=%d\n", + (int)get_ksu_state()); #ifdef CONFIG_KSU_CMDLINE - if (!get_ksu_state()) { - pr_info_once("drivers is disabled."); - return 0; - } + if (!get_ksu_state()) { + pr_info_once("drivers is disabled."); + return 0; + } #endif #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 #ifdef CONFIG_KSU_SUSFS - susfs_init(); + susfs_init(); #endif - ksu_core_init(); + ksu_core_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(); - ksu_sucompat_init(); + ksu_sucompat_init(); #ifdef CONFIG_KSU_KPROBES_HOOK - ksu_ksud_init(); + ksu_ksud_init(); #else - pr_debug("init ksu driver\n"); + pr_debug("init ksu driver\n"); #endif #ifdef CONFIG_KSU_TRACEPOINT_HOOK @@ -112,36 +112,38 @@ int __init kernelsu_init(void) #ifdef MODULE #ifndef CONFIG_KSU_DEBUG - kobject_del(&THIS_MODULE->mkobj.kobj); + kobject_del(&THIS_MODULE->mkobj.kobj); #endif #endif - return 0; + return 0; } void kernelsu_exit(void) { #ifdef CONFIG_KSU_CMDLINE - if (!get_ksu_state()) { - return; - } + if (!get_ksu_state()) { + return; + } #endif - ksu_allowlist_exit(); + ksu_allowlist_exit(); - ksu_throne_tracker_exit(); + ksu_observer_exit(); - destroy_workqueue(ksu_workqueue); + ksu_throne_tracker_exit(); + + destroy_workqueue(ksu_workqueue); #ifdef CONFIG_KSU_KPROBES_HOOK - ksu_ksud_exit(); + ksu_ksud_exit(); #endif #ifdef CONFIG_KSU_TRACEPOINT_HOOK ksu_trace_unregister(); #endif - ksu_sucompat_exit(); + ksu_sucompat_exit(); - ksu_core_exit(); + ksu_core_exit(); } module_init(kernelsu_init); diff --git a/kernel/ksu.h b/kernel/ksu.h index 72d60b29..ca9357d4 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -7,35 +7,12 @@ #define KERNEL_SU_VERSION KSU_VERSION #define KERNEL_SU_OPTION 0xDEADBEEF -#define CMD_GRANT_ROOT 0 -#define CMD_BECOME_MANAGER 1 -#define CMD_GET_VERSION 2 -#define CMD_ALLOW_SU 3 -#define CMD_DENY_SU 4 -#define CMD_GET_ALLOW_LIST 5 -#define CMD_GET_DENY_LIST 6 -#define CMD_REPORT_EVENT 7 -#define CMD_SET_SEPOLICY 8 -#define CMD_CHECK_SAFEMODE 9 -#define CMD_GET_APP_PROFILE 10 -#define CMD_SET_APP_PROFILE 11 -#define CMD_UID_GRANTED_ROOT 12 -#define CMD_UID_SHOULD_UMOUNT 13 -#define CMD_IS_SU_ENABLED 14 -#define CMD_ENABLE_SU 15 +extern bool ksu_uid_scanner_enabled; #ifdef CONFIG_KSU_MANUAL_SU #define CMD_MANUAL_SU_REQUEST 50 #endif -#define CMD_GET_FULL_VERSION 0xC0FFEE1A - -#define CMD_ENABLE_KPM 100 -#define CMD_HOOK_TYPE 101 -#define CMD_DYNAMIC_MANAGER 103 -#define CMD_GET_MANAGERS 104 -#define CMD_ENABLE_UID_SCANNER 105 - #define EVENT_POST_FS_DATA 1 #define EVENT_BOOT_COMPLETED 2 #define EVENT_MODULE_MOUNTED 3 @@ -56,6 +33,10 @@ #define DYNAMIC_MANAGER_OP_GET 1 #define DYNAMIC_MANAGER_OP_CLEAR 2 +#define UID_SCANNER_OP_GET_STATUS 0 +#define UID_SCANNER_OP_TOGGLE 1 +#define UID_SCANNER_OP_CLEAR_ENV 2 + struct dynamic_manager_user_config { unsigned int operation; unsigned int size; @@ -71,67 +52,67 @@ struct manager_list_info { }; struct root_profile { - int32_t uid; - int32_t gid; + int32_t uid; + int32_t gid; - int32_t groups_count; - int32_t groups[KSU_MAX_GROUPS]; + int32_t groups_count; + int32_t groups[KSU_MAX_GROUPS]; - // kernel_cap_t is u32[2] for capabilities v3 - struct { - u64 effective; - u64 permitted; - u64 inheritable; - } capabilities; + // kernel_cap_t is u32[2] for capabilities v3 + struct { + u64 effective; + u64 permitted; + u64 inheritable; + } capabilities; - char selinux_domain[KSU_SELINUX_DOMAIN]; + char selinux_domain[KSU_SELINUX_DOMAIN]; - int32_t namespaces; + int32_t namespaces; }; struct non_root_profile { - bool umount_modules; + bool umount_modules; }; struct app_profile { - // It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this. - u32 version; + // It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this. + u32 version; - // this is usually the package of the app, but can be other value for special apps - char key[KSU_MAX_PACKAGE_NAME]; - int32_t current_uid; - bool allow_su; + // this is usually the package of the app, but can be other value for special apps + char key[KSU_MAX_PACKAGE_NAME]; + int32_t current_uid; + bool allow_su; - union { - struct { - bool use_default; - char template_name[KSU_MAX_PACKAGE_NAME]; + union { + struct { + bool use_default; + char template_name[KSU_MAX_PACKAGE_NAME]; - struct root_profile profile; - } rp_config; + struct root_profile profile; + } rp_config; - struct { - bool use_default; + struct { + bool use_default; - struct non_root_profile profile; - } nrp_config; - }; + struct non_root_profile profile; + } nrp_config; + }; }; bool ksu_queue_work(struct work_struct *work); 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 +#endif \ No newline at end of file diff --git a/kernel/ksu_trace.c b/kernel/ksu_trace.c index e4225167..4055877b 100644 --- a/kernel/ksu_trace.c +++ b/kernel/ksu_trace.c @@ -16,7 +16,7 @@ extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, void ksu_trace_execveat_hook_callback(void *data, int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags) { - ksu_handle_execveat(fd, filename_ptr, argv, envp, flags); + ksu_handle_execveat(fd, filename_ptr, argv, envp, flags); } void ksu_trace_faccessat_hook_callback(void *data, int *dfd, const char __user **filename_user, @@ -28,8 +28,8 @@ void ksu_trace_faccessat_hook_callback(void *data, int *dfd, const char __user * void ksu_trace_sys_read_hook_callback(void *data, unsigned int fd, char __user **buf_ptr, size_t *count_ptr) { - if (unlikely(ksu_vfs_read_hook)) - ksu_handle_sys_read(fd, buf_ptr, count_ptr); + if (unlikely(ksu_vfs_read_hook)) + ksu_handle_sys_read(fd, buf_ptr, count_ptr); } void ksu_trace_stat_hook_callback(void *data, int *dfd, const char __user **filename_user, @@ -41,8 +41,8 @@ void ksu_trace_stat_hook_callback(void *data, int *dfd, const char __user **file void ksu_trace_input_hook_callback(void *data, unsigned int *type, unsigned int *code, int *value) { - if (unlikely(ksu_input_hook)) - ksu_handle_input_handle_event(type, code, value); + if (unlikely(ksu_input_hook)) + ksu_handle_input_handle_event(type, code, value); } // end tracepoint callback functions diff --git a/kernel/ksu_trace.h b/kernel/ksu_trace.h index 06159b3c..77425638 100644 --- a/kernel/ksu_trace.h +++ b/kernel/ksu_trace.h @@ -8,24 +8,24 @@ #include DECLARE_TRACE(ksu_trace_execveat_hook, - TP_PROTO(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags), - TP_ARGS(fd, filename_ptr, argv, envp, flags)); + TP_PROTO(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags), + TP_ARGS(fd, filename_ptr, argv, envp, flags)); DECLARE_TRACE(ksu_trace_faccessat_hook, - TP_PROTO(int *dfd, const char __user **filename_user, int *mode, int *flags), - TP_ARGS(dfd, filename_user, mode, flags)); + TP_PROTO(int *dfd, const char __user **filename_user, int *mode, int *flags), + TP_ARGS(dfd, filename_user, mode, flags)); DECLARE_TRACE(ksu_trace_sys_read_hook, - TP_PROTO(unsigned int fd, char __user **buf_ptr, size_t *count_ptr), - TP_ARGS(fd, buf_ptr, count_ptr)); + TP_PROTO(unsigned int fd, char __user **buf_ptr, size_t *count_ptr), + TP_ARGS(fd, buf_ptr, count_ptr)); DECLARE_TRACE(ksu_trace_stat_hook, - TP_PROTO(int *dfd, const char __user **filename_user, int *flags), - TP_ARGS(dfd, filename_user, flags)); + TP_PROTO(int *dfd, const char __user **filename_user, int *flags), + TP_ARGS(dfd, filename_user, flags)); DECLARE_TRACE(ksu_trace_input_hook, - TP_PROTO(unsigned int *type, unsigned int *code, int *value), - TP_ARGS(type, code, value)); + TP_PROTO(unsigned int *type, unsigned int *code, int *value), + TP_ARGS(type, code, value)); #endif /* _KSU_TRACE_H */ diff --git a/kernel/ksud.c b/kernel/ksud.c index d7078460..a170ee52 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -28,27 +28,27 @@ #include "selinux/selinux.h" 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); @@ -75,19 +75,20 @@ static bool is_boot_phase = true; void on_post_fs_data(void) { - static bool done = false; - if (done) { - pr_info("%s already done\n", __func__); - return; - } - done = true; - pr_info("%s!\n", __func__); - ksu_load_allow_list(); - // sanity check, this may influence the performance - stop_input_hook(); + static bool done = false; + if (done) { + pr_info("%s already done\n", __func__); + return; + } + done = true; + pr_info("%s!\n", __func__); + ksu_load_allow_list(); + ksu_observer_init(); + // sanity check, this may influence the performance + stop_input_hook(); - ksu_devpts_sid = ksu_get_devpts_sid(); - pr_info("devpts sid: %d\n", ksu_devpts_sid); + ksu_devpts_sid = ksu_get_devpts_sid(); + pr_info("devpts sid: %d\n", ksu_devpts_sid); // End of boot state is_boot_phase = false; @@ -95,14 +96,14 @@ void on_post_fs_data(void) 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; }; // since _ksud handler only uses argv and envp for comparisons @@ -110,158 +111,158 @@ struct user_arg_ptr { // adapted from ksu_handle_execveat_ksud static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const char *envp, size_t envp_len) { - 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; - // return early when disabled - if (!ksu_execveat_hook) - return 0; + // return early when disabled + if (!ksu_execveat_hook) + return 0; - if (!filename) - return 0; + if (!filename) + return 0; - // debug! remove me! - pr_info("%s: filename: %s argv1: %s envp_len: %zu\n", __func__, filename, argv1, envp_len); + // debug! remove me! + pr_info("%s: filename: %s argv1: %s envp_len: %zu\n", __func__, filename, argv1, envp_len); #ifdef CONFIG_KSU_DEBUG - const char *envp_n = envp; - unsigned int envc = 1; - do { - pr_info("%s: envp[%d]: %s\n", __func__, envc, envp_n); - envp_n += strlen(envp_n) + 1; - envc++; - } while (envp_n < envp + 256); + const char *envp_n = envp; + unsigned int envc = 1; + do { + pr_info("%s: envp[%d]: %s\n", __func__, envc, envp_n); + envp_n += strlen(envp_n) + 1; + envc++; + } while (envp_n < envp + 256); #endif - if (init_second_stage_executed) - goto first_app_process; + if (init_second_stage_executed) + goto first_app_process; - // /system/bin/init with argv1 - if (!init_second_stage_executed - && (!memcmp(filename, system_bin_init, sizeof(system_bin_init) - 1))) { - if (argv1 && !strcmp(argv1, "second_stage")) { - pr_info("%s: /system/bin/init second_stage executed\n", __func__); - apply_kernelsu_rules(); - init_second_stage_executed = true; - ksu_android_ns_fs_check(); - } - } + // /system/bin/init with argv1 + if (!init_second_stage_executed + && (!memcmp(filename, system_bin_init, sizeof(system_bin_init) - 1))) { + if (argv1 && !strcmp(argv1, "second_stage")) { + pr_info("%s: /system/bin/init second_stage executed\n", __func__); + apply_kernelsu_rules(); + init_second_stage_executed = true; + ksu_android_ns_fs_check(); + } + } - // /init with argv1 - if (!init_second_stage_executed - && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { - if (argv1 && !strcmp(argv1, "--second-stage")) { - pr_info("%s: /init --second-stage executed\n", __func__); - apply_kernelsu_rules(); - init_second_stage_executed = true; - ksu_android_ns_fs_check(); - } - } + // /init with argv1 + if (!init_second_stage_executed + && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { + if (argv1 && !strcmp(argv1, "--second-stage")) { + pr_info("%s: /init --second-stage executed\n", __func__); + apply_kernelsu_rules(); + init_second_stage_executed = true; + ksu_android_ns_fs_check(); + } + } - if (!envp || !envp_len) - goto first_app_process; + if (!envp || !envp_len) + goto first_app_process; - // /init without argv1/useless-argv1 but usable envp - // untested! TODO: test and debug me! - if (!init_second_stage_executed && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { - - // we hunt for "INIT_SECOND_STAGE" - const char *envp_n = envp; - unsigned int envc = 1; - do { - if (strstarts(envp_n, "INIT_SECOND_STAGE")) - break; - envp_n += strlen(envp_n) + 1; - envc++; - } while (envp_n < envp + envp_len); - pr_info("%s: envp[%d]: %s\n", __func__, envc, envp_n); - - if (!strcmp(envp_n, "INIT_SECOND_STAGE=1") - || !strcmp(envp_n, "INIT_SECOND_STAGE=true") ) { - pr_info("%s: /init +envp: INIT_SECOND_STAGE executed\n", __func__); - apply_kernelsu_rules(); - init_second_stage_executed = true; - ksu_android_ns_fs_check(); - } - } + // /init without argv1/useless-argv1 but usable envp + // untested! TODO: test and debug me! + if (!init_second_stage_executed && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { + + // we hunt for "INIT_SECOND_STAGE" + const char *envp_n = envp; + unsigned int envc = 1; + do { + if (strstarts(envp_n, "INIT_SECOND_STAGE")) + break; + envp_n += strlen(envp_n) + 1; + envc++; + } while (envp_n < envp + envp_len); + pr_info("%s: envp[%d]: %s\n", __func__, envc, envp_n); + + if (!strcmp(envp_n, "INIT_SECOND_STAGE=1") + || !strcmp(envp_n, "INIT_SECOND_STAGE=true") ) { + pr_info("%s: /init +envp: INIT_SECOND_STAGE executed\n", __func__); + apply_kernelsu_rules(); + init_second_stage_executed = true; + ksu_android_ns_fs_check(); + } + } first_app_process: - if (first_app_process && !memcmp(filename, app_process, sizeof(app_process) - 1)) { - first_app_process = false; - pr_info("%s: exec app_process, /data prepared, second_stage: %d\n", __func__, init_second_stage_executed); - on_post_fs_data(); - stop_execve_hook(); - } + if (first_app_process && !memcmp(filename, app_process, sizeof(app_process) - 1)) { + first_app_process = false; + pr_info("%s: exec app_process, /data prepared, second_stage: %d\n", __func__, init_second_stage_executed); + on_post_fs_data(); + stop_execve_hook(); + } - return 0; + return 0; } int ksu_handle_pre_ksud(const char *filename) { - if (likely(!ksu_execveat_hook)) - return 0; + if (likely(!ksu_execveat_hook)) + return 0; - // not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy) - // return 0; - if (likely(strcmp(filename, "/system/bin/init") && strcmp(filename, "/init") - && !strstarts(filename, "/system/bin/app_process") )) - return 0; + // not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy) + // return 0; + if (likely(strcmp(filename, "/system/bin/init") && strcmp(filename, "/init") + && !strstarts(filename, "/system/bin/app_process") )) + return 0; - if (!current || !current->mm) - return 0; + if (!current || !current->mm) + return 0; - // https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/mm_types.h#L429 - // unsigned long arg_start, arg_end, env_start, env_end; - unsigned long arg_start = current->mm->arg_start; - unsigned long arg_end = current->mm->arg_end; - unsigned long env_start = current->mm->env_start; - unsigned long env_end = current->mm->env_end; + // https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/mm_types.h#L429 + // unsigned long arg_start, arg_end, env_start, env_end; + unsigned long arg_start = current->mm->arg_start; + unsigned long arg_end = current->mm->arg_end; + unsigned long env_start = current->mm->env_start; + unsigned long env_end = current->mm->env_end; - size_t arg_len = arg_end - arg_start; - size_t envp_len = env_end - env_start; + size_t arg_len = arg_end - arg_start; + size_t envp_len = env_end - env_start; - if (arg_len <= 0 || envp_len <= 0) // this wont make sense, filter it - return 0; + if (arg_len <= 0 || envp_len <= 0) // this wont make sense, filter it + return 0; - #define ARGV_MAX 32 // this is enough for argv1 - #define ENVP_MAX 256 // this is enough for INIT_SECOND_STAGE - char args[ARGV_MAX]; - size_t argv_copy_len = (arg_len > ARGV_MAX) ? ARGV_MAX : arg_len; - char envp[ENVP_MAX]; - size_t envp_copy_len = (envp_len > ENVP_MAX) ? ENVP_MAX : envp_len; + #define ARGV_MAX 32 // this is enough for argv1 + #define ENVP_MAX 256 // this is enough for INIT_SECOND_STAGE + char args[ARGV_MAX]; + size_t argv_copy_len = (arg_len > ARGV_MAX) ? ARGV_MAX : arg_len; + char envp[ENVP_MAX]; + size_t envp_copy_len = (envp_len > ENVP_MAX) ? ENVP_MAX : envp_len; - // we cant use strncpy on here, else it will truncate once it sees \0 - if (ksu_copy_from_user_retry(args, (void __user *)arg_start, argv_copy_len)) - return 0; + // we cant use strncpy on here, else it will truncate once it sees \0 + if (ksu_copy_from_user_retry(args, (void __user *)arg_start, argv_copy_len)) + return 0; - if (ksu_copy_from_user_retry(envp, (void __user *)env_start, envp_copy_len)) - return 0; + if (ksu_copy_from_user_retry(envp, (void __user *)env_start, envp_copy_len)) + return 0; - args[ARGV_MAX - 1] = '\0'; - envp[ENVP_MAX - 1] = '\0'; + args[ARGV_MAX - 1] = '\0'; + envp[ENVP_MAX - 1] = '\0'; - // we only need argv1 ! - // abuse strlen here since it only gets length up to \0 - char *argv1 = args + strlen(args) + 1; - if (argv1 >= args + argv_copy_len) // out of bounds! - argv1 = ""; + // we only need argv1 ! + // abuse strlen here since it only gets length up to \0 + char *argv1 = args + strlen(args) + 1; + if (argv1 >= args + argv_copy_len) // out of bounds! + argv1 = ""; - return ksu_handle_bprm_ksud(filename, argv1, envp, envp_copy_len); + return ksu_handle_bprm_ksud(filename, argv1, envp, envp_copy_len); } 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) { - // this is now handled via security_bprm_check - // we only keep this for the sake of old hooks. - return 0; + // this is now handled via security_bprm_check + // we only keep this for the sake of old hooks. + return 0; } static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *); @@ -270,398 +271,398 @@ 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; } 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 CONFIG_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 CONFIG_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 (*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(); - } - } - } + // 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; } #ifdef CONFIG_KSU_KPROBES_HOOK static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) { - /* - asmlinkage int sys_execve(const char __user *filenamei, - const char __user *const __user *argv, - const char __user *const __user *envp, struct pt_regs *regs) - */ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user *filename_user = (const char __user *)PT_REGS_PARM1(real_regs); - const char __user *const __user *__argv = (const char __user *const __user *)PT_REGS_PARM2(real_regs); - const char __user *const __user *__envp = (const char __user *const __user *)PT_REGS_PARM3(real_regs); - char path[32]; + /* + asmlinkage int sys_execve(const char __user *filenamei, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) + */ + struct pt_regs *real_regs = PT_REAL_REGS(regs); + const char __user *filename_user = (const char __user *)PT_REGS_PARM1(real_regs); + const char __user *const __user *__argv = (const char __user *const __user *)PT_REGS_PARM2(real_regs); + const char __user *const __user *__envp = (const char __user *const __user *)PT_REGS_PARM3(real_regs); + char path[32]; - if (!filename_user) - return 0; + if (!filename_user) + return 0; // filename stage - if (ksu_copy_from_user_retry(path, filename_user, sizeof(path))) - return 0; + if (ksu_copy_from_user_retry(path, filename_user, sizeof(path))) + return 0; - path[sizeof(path) - 1] = '\0'; + path[sizeof(path) - 1] = '\0'; - // not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy) - // we dont care !! - if (likely(strcmp(path, "/system/bin/init") && strcmp(path, "/init") - && !strstarts(path, "/system/bin/app_process") )) - return 0; + // not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy) + // we dont care !! + if (likely(strcmp(path, "/system/bin/init") && strcmp(path, "/init") + && !strstarts(path, "/system/bin/app_process") )) + return 0; // argv stage - char argv1[32] = {0}; - // memzero_explicit(argv1, 32); - if (__argv) { - const char __user *arg1_user = NULL; - // grab argv[1] pointer - // this looks like - /* - * 0x1000 ./program << this is __argv - * 0x1001 -o - * 0x1002 arg - */ - if (ksu_copy_from_user_retry(&arg1_user, __argv + 1, sizeof(arg1_user))) - goto no_argv1; // copy argv[1] pointer fail, probably no argv1 !! + char argv1[32] = {0}; + // memzero_explicit(argv1, 32); + if (__argv) { + const char __user *arg1_user = NULL; + // grab argv[1] pointer + // this looks like + /* + * 0x1000 ./program << this is __argv + * 0x1001 -o + * 0x1002 arg + */ + if (ksu_copy_from_user_retry(&arg1_user, __argv + 1, sizeof(arg1_user))) + goto no_argv1; // copy argv[1] pointer fail, probably no argv1 !! - if (arg1_user) - ksu_copy_from_user_retry(argv1, arg1_user, sizeof(argv1)); - } + if (arg1_user) + ksu_copy_from_user_retry(argv1, arg1_user, sizeof(argv1)); + } no_argv1: - argv1[sizeof(argv1) - 1] = '\0'; + argv1[sizeof(argv1) - 1] = '\0'; // envp stage - #define ENVP_MAX 256 - char envp[ENVP_MAX] = {0}; - char *dst = envp; - size_t envp_len = 0; - int i = 0; // to track user pointer offset from __envp + #define ENVP_MAX 256 + char envp[ENVP_MAX] = {0}; + char *dst = envp; + size_t envp_len = 0; + int i = 0; // to track user pointer offset from __envp - // memzero_explicit(envp, ENVP_MAX); + // memzero_explicit(envp, ENVP_MAX); - if (__envp) { - do { - const char __user *env_entry_user = NULL; - // this is also like argv above - /* - * 0x1001 PATH=/bin - * 0x1002 VARIABLE=value - * 0x1002 some_more_env_var=1 - */ + if (__envp) { + do { + const char __user *env_entry_user = NULL; + // this is also like argv above + /* + * 0x1001 PATH=/bin + * 0x1002 VARIABLE=value + * 0x1002 some_more_env_var=1 + */ - // check if pointer exists - if (ksu_copy_from_user_retry(&env_entry_user, __envp + i, sizeof(env_entry_user))) - break; + // check if pointer exists + if (ksu_copy_from_user_retry(&env_entry_user, __envp + i, sizeof(env_entry_user))) + break; - // check if no more env entry - if (!env_entry_user) - break; - - // probably redundant to while condition but ok - if (envp_len >= ENVP_MAX - 1) - break; + // check if no more env entry + if (!env_entry_user) + break; + + // probably redundant to while condition but ok + if (envp_len >= ENVP_MAX - 1) + break; - // copy strings from env_entry_user pointer that we collected - // also break if failed - if (ksu_copy_from_user_retry(dst, env_entry_user, ENVP_MAX - envp_len)) - break; + // copy strings from env_entry_user pointer that we collected + // also break if failed + if (ksu_copy_from_user_retry(dst, env_entry_user, ENVP_MAX - envp_len)) + break; - // get the length of that new copy above - // get lngth of dst as far as ENVP_MAX - current collected envp_len - size_t len = strnlen(dst, ENVP_MAX - envp_len); - if (envp_len + len + 1 > ENVP_MAX) - break; // if more than 255 bytes, bail + // get the length of that new copy above + // get lngth of dst as far as ENVP_MAX - current collected envp_len + size_t len = strnlen(dst, ENVP_MAX - envp_len); + if (envp_len + len + 1 > ENVP_MAX) + break; // if more than 255 bytes, bail - dst[len] = '\0'; - // collect total number of copied strings - envp_len = envp_len + len + 1; - // increment dst address since we need to put something on next iter - dst = dst + len + 1; - // pointer walk, __envp + i - i++; - } while (envp_len < ENVP_MAX); - } + dst[len] = '\0'; + // collect total number of copied strings + envp_len = envp_len + len + 1; + // increment dst address since we need to put something on next iter + dst = dst + len + 1; + // pointer walk, __envp + i + i++; + } while (envp_len < ENVP_MAX); + } - /* - at this point, we shoul've collected envp from - * 0x1001 PATH=/bin - * 0x1002 VARIABLE=value - * 0x1002 some_more_env_var=1 - to - * 0x1234 PATH=/bin\0VARIABLE=value\0some_more_env_var=1\0\0\0\0 - */ + /* + at this point, we shoul've collected envp from + * 0x1001 PATH=/bin + * 0x1002 VARIABLE=value + * 0x1002 some_more_env_var=1 + to + * 0x1234 PATH=/bin\0VARIABLE=value\0some_more_env_var=1\0\0\0\0 + */ - envp[ENVP_MAX - 1] = '\0'; + envp[ENVP_MAX - 1] = '\0'; #ifdef CONFIG_KSU_DEBUG - pr_info("%s: filename: %s argv[1]:%s envp_len: %zu\n", __func__, path, argv1, envp_len); + pr_info("%s: filename: %s argv[1]:%s envp_len: %zu\n", __func__, path, argv1, envp_len); #endif - return ksu_handle_bprm_ksud(path, argv1, envp, envp_len); + return ksu_handle_bprm_ksud(path, argv1, envp, envp_len); } 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); } #else static int ksu_execve_ksud_common(const char __user *filename_user, - struct user_arg_ptr *argv) + struct user_arg_ptr *argv) { - struct filename filename_in, *filename_p; - char path[32]; - long len; - - // return early if disabled. - if (!ksu_execveat_hook) { - return 0; - } + struct filename filename_in, *filename_p; + char path[32]; + long len; + + // return early if disabled. + if (!ksu_execveat_hook) { + return 0; + } - if (!filename_user) - return 0; + if (!filename_user) + return 0; - len = ksu_strncpy_from_user_nofault(path, filename_user, 32); - if (len <= 0) - return 0; + len = ksu_strncpy_from_user_nofault(path, filename_user, 32); + if (len <= 0) + return 0; - path[sizeof(path) - 1] = '\0'; + path[sizeof(path) - 1] = '\0'; - // this is because ksu_handle_execveat_ksud calls it filename->name - filename_in.name = path; - filename_p = &filename_in; + // this is because ksu_handle_execveat_ksud calls it filename->name + filename_in.name = path; + filename_p = &filename_in; - return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, argv, NULL, NULL); + return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, argv, NULL, NULL); } int __maybe_unused ksu_handle_execve_ksud(const char __user *filename_user, - const char __user *const __user *__argv) + const char __user *const __user *__argv) { - struct user_arg_ptr argv = { .ptr.native = __argv }; - return ksu_execve_ksud_common(filename_user, &argv); + struct user_arg_ptr argv = { .ptr.native = __argv }; + return ksu_execve_ksud_common(filename_user, &argv); } #if defined(CONFIG_COMPAT) && defined(CONFIG_64BIT) int __maybe_unused ksu_handle_compat_execve_ksud(const char __user *filename_user, - const compat_uptr_t __user *__argv) + const compat_uptr_t __user *__argv) { - struct user_arg_ptr argv = { .ptr.compat = __argv }; - return ksu_execve_ksud_common(filename_user, &argv); + struct user_arg_ptr argv = { .ptr.compat = __argv }; + return ksu_execve_ksud_common(filename_user, &argv); } #endif /* COMPAT & 64BIT */ @@ -670,22 +671,22 @@ int __maybe_unused ksu_handle_compat_execve_ksud(const char __user *filename_use static void stop_vfs_read_hook(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - 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) { #ifdef CONFIG_KSU_KPROBES_HOOK - 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 - pr_info("stop execve_hook\n"); - ksu_execveat_hook = false; + pr_info("stop execve_hook\n"); + ksu_execveat_hook = false; #endif #ifdef CONFIG_KSU_SUSFS_SUS_SU susfs_is_sus_su_ready = true; @@ -696,17 +697,17 @@ static void stop_execve_hook(void) static void stop_input_hook(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - static bool input_hook_stopped = false; - if (input_hook_stopped) { - return; - } - input_hook_stopped = true; - bool ret = schedule_work(&stop_input_hook_work); - pr_info("unregister input kprobe: %d!\n", ret); + static bool input_hook_stopped = false; + if (input_hook_stopped) { + return; + } + input_hook_stopped = true; + bool ret = schedule_work(&stop_input_hook_work); + pr_info("unregister input kprobe: %d!\n", ret); #else - if (!ksu_input_hook) { return; } - ksu_input_hook = false; - pr_info("stop input_hook\n"); + if (!ksu_input_hook) { return; } + ksu_input_hook = false; + pr_info("stop input_hook\n"); #endif } @@ -714,31 +715,31 @@ static void stop_input_hook(void) void ksu_ksud_init(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - 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) { #ifdef CONFIG_KSU_KPROBES_HOOK - 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; + is_boot_phase = false; volumedown_pressed_count = 0; } diff --git a/kernel/manager.h b/kernel/manager.h index 57f43418..4c9e9570 100644 --- a/kernel/manager.h +++ b/kernel/manager.h @@ -15,28 +15,31 @@ 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; } 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)); } static inline uid_t ksu_get_manager_uid(void) { - return ksu_manager_uid; + return ksu_manager_uid; } static inline void ksu_set_manager_uid(uid_t uid) { - ksu_manager_uid = uid; + ksu_manager_uid = uid; } 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); +void ksu_observer_exit(void); + #endif \ No newline at end of file diff --git a/kernel/manager_sign.h b/kernel/manager_sign.h index 41c06d98..3dc97d1f 100644 --- a/kernel/manager_sign.h +++ b/kernel/manager_sign.h @@ -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 37bba2c1..57724213 100644 --- a/kernel/manual_su.c +++ b/kernel/manual_su.c @@ -121,9 +121,9 @@ static char* ksu_generate_auth_token(void) } #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; @@ -204,9 +204,9 @@ static int handle_token_generation(struct manual_su_request *request) } #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"); diff --git a/kernel/pkg_observer.c b/kernel/pkg_observer.c new file mode 100644 index 00000000..e0641332 --- /dev/null +++ b/kernel/pkg_observer.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include "klog.h" // IWYU pragma: keep +#include "ksu.h" +#include "throne_tracker.h" +#include "throne_comm.h" + +#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; +}; + +static struct fsnotify_group *g; + +static int ksu_handle_inode_event(struct fsnotify_mark *mark, u32 mask, + struct inode *inode, struct inode *dir, + const struct qstr *file_name, u32 cookie) +{ + if (!file_name) + return 0; + if (mask & FS_ISDIR) + return 0; + if (file_name->len == 13 && + !memcmp(file_name->name, "packages.list", 13)) { + pr_info("packages.list detected: %d\n", mask); + if (ksu_uid_scanner_enabled) { + ksu_request_userspace_scan(); + } + track_throne(); + } + return 0; +} + +static const struct fsnotify_ops ksu_ops = { + .handle_inode_event = ksu_handle_inode_event, +}; + +static int add_mark_on_inode(struct inode *inode, u32 mask, + struct fsnotify_mark **out) +{ + struct fsnotify_mark *m; + + m = kzalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return -ENOMEM; + + fsnotify_init_mark(m, g); + m->mask = mask; + + if (fsnotify_add_inode_mark(m, inode, 0)) { + fsnotify_put_mark(m); + return -EINVAL; + } + *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); + + 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)); + } +} + +static struct watch_dir g_watch = { .path = "/data/system", + .mask = MASK_SYSTEM }; + +int ksu_observer_init(void) +{ + int ret = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) + g = fsnotify_alloc_group(&ksu_ops, 0); +#else + g = fsnotify_alloc_group(&ksu_ops); +#endif + if (IS_ERR(g)) + return PTR_ERR(g); + + ret = watch_one_dir(&g_watch); + pr_info("observer init done\n"); + return 0; +} + +void ksu_observer_exit(void) +{ + unwatch_one_dir(&g_watch); + fsnotify_put_group(g); + pr_info("observer exit done\n"); +} \ No newline at end of file diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index ca2c0d48..01b3e9b0 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -20,138 +20,138 @@ static struct policydb *get_policydb(void) { - struct policydb *db; + struct policydb *db; // selinux_state does not exists before 4.19 #ifdef KSU_COMPAT_USE_SELINUX_STATE #ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS - struct selinux_policy *policy = selinux_state.policy; - db = &policy->policydb; + struct selinux_policy *policy = selinux_state.policy; + db = &policy->policydb; #else - struct selinux_ss *ss = selinux_state.ss; - db = &ss->policydb; + struct selinux_ss *ss = selinux_state.ss; + db = &ss->policydb; #endif #else - db = &policydb; + db = &policydb; #endif - return db; + return db; } static DEFINE_MUTEX(ksu_rules); void apply_kernelsu_rules(void) { - struct policydb *db; + struct policydb *db; - if (!getenforce()) { - pr_info("SELinux permissive or disabled, apply rules!\n"); - } + if (!getenforce()) { + pr_info("SELinux permissive or disabled, apply rules!\n"); + } - mutex_lock(&ksu_rules); + mutex_lock(&ksu_rules); - db = get_policydb(); + db = get_policydb(); - ksu_permissive(db, KERNEL_SU_DOMAIN); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); + ksu_permissive(db, KERNEL_SU_DOMAIN); + ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); + ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); + ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); - // Create unconstrained file type - ksu_type(db, KERNEL_SU_FILE, "file_type"); - ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject"); - ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL); + // Create unconstrained file type + ksu_type(db, KERNEL_SU_FILE, "file_type"); + ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject"); + ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL); - // allow all! - ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); + // allow all! + ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); - // allow us do any ioctl - if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL); - } + // allow us do any ioctl + if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL); + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL); + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); + ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL); + } - // we need to save allowlist in /data/adb/ksu - ksu_allow(db, "kernel", "adb_data_file", "dir", ALL); - ksu_allow(db, "kernel", "adb_data_file", "file", ALL); - // we need to search /data/app - ksu_allow(db, "kernel", "apk_data_file", "file", "open"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "open"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "read"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "search"); - // we may need to do mount on shell - ksu_allow(db, "kernel", "shell_data_file", "file", ALL); - // we need to read /data/system/packages.list - ksu_allow(db, "kernel", "kernel", "capability", "dac_override"); - // Android 10+: - // http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512 - ksu_allow(db, "kernel", "packages_list_file", "file", ALL); - // Kernel 4.4 - ksu_allow(db, "kernel", "packages_list_file", "dir", ALL); - // Android 9-: - // http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360 - ksu_allow(db, "kernel", "system_data_file", "file", ALL); - ksu_allow(db, "kernel", "system_data_file", "dir", ALL); - // our ksud triggered by init - ksu_allow(db, "init", "adb_data_file", "file", ALL); - ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289 - ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL); + // we need to save allowlist in /data/adb/ksu + ksu_allow(db, "kernel", "adb_data_file", "dir", ALL); + ksu_allow(db, "kernel", "adb_data_file", "file", ALL); + // we need to search /data/app + ksu_allow(db, "kernel", "apk_data_file", "file", "open"); + ksu_allow(db, "kernel", "apk_data_file", "dir", "open"); + ksu_allow(db, "kernel", "apk_data_file", "dir", "read"); + ksu_allow(db, "kernel", "apk_data_file", "dir", "search"); + // we may need to do mount on shell + ksu_allow(db, "kernel", "shell_data_file", "file", ALL); + // we need to read /data/system/packages.list + ksu_allow(db, "kernel", "kernel", "capability", "dac_override"); + // Android 10+: + // http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512 + ksu_allow(db, "kernel", "packages_list_file", "file", ALL); + // Kernel 4.4 + ksu_allow(db, "kernel", "packages_list_file", "dir", ALL); + // Android 9-: + // http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360 + ksu_allow(db, "kernel", "system_data_file", "file", ALL); + ksu_allow(db, "kernel", "system_data_file", "dir", ALL); + // our ksud triggered by init + ksu_allow(db, "init", "adb_data_file", "file", ALL); + ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289 + ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL); - // we need to umount modules in zygote - ksu_allow(db, "zygote", "adb_data_file", "dir", "search"); + // we need to umount modules in zygote + ksu_allow(db, "zygote", "adb_data_file", "dir", "search"); - // copied from Magisk rules - // suRights - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); + // copied from Magisk rules + // suRights + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); + ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); - // allowLog - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); + // allowLog + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); + ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); - // dumpsys - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); + // dumpsys + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); - // bootctl - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", - "getattr"); + // bootctl + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); + ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", + "getattr"); - // For mounting loop devices, mirrors, tmpfs - ksu_allow(db, "kernel", ALL, "file", "read"); - ksu_allow(db, "kernel", ALL, "file", "write"); + // For mounting loop devices, mirrors, tmpfs + ksu_allow(db, "kernel", ALL, "file", "read"); + ksu_allow(db, "kernel", ALL, "file", "write"); - // Allow all binder transactions - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); + // Allow all binder transactions + ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); - // 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"); + // 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"); - // https://android-review.googlesource.com/c/platform/system/logging/+/3725346 - ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr"); + // https://android-review.googlesource.com/c/platform/system/logging/+/3725346 + ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr"); #ifdef CONFIG_KSU_SUSFS - // Allow umount in zygote process without installing zygisk - ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount"); - susfs_set_kernel_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_kernel_sid(); + susfs_set_init_sid(); + susfs_set_ksu_sid(); + susfs_set_zygote_sid(); #endif - mutex_unlock(&ksu_rules); + mutex_unlock(&ksu_rules); } #define MAX_SEPOL_LEN 128 @@ -171,375 +171,375 @@ extern bool ksu_is_compat __read_mostly; // armv7l kernel compat #ifdef CONFIG_64BIT -#define usize u64 +#define usize u64 #else -#define usize u32 +#define usize u32 #endif struct sepol_data { - u32 cmd; - u32 subcmd; - usize field_sepol1; - usize field_sepol2; - usize field_sepol3; - usize field_sepol4; - usize field_sepol5; - usize field_sepol6; - usize field_sepol7; + u32 cmd; + u32 subcmd; + usize field_sepol1; + usize field_sepol2; + usize field_sepol3; + usize field_sepol4; + usize field_sepol5; + usize field_sepol6; + usize field_sepol7; }; // ksud 32-bit on arm64 kernel struct __maybe_unused sepol_data_compat { - u32 cmd; - u32 subcmd; - u32 field_sepol1; - u32 field_sepol2; - u32 field_sepol3; - u32 field_sepol4; - u32 field_sepol5; - u32 field_sepol6; - u32 field_sepol7; + u32 cmd; + u32 subcmd; + u32 field_sepol1; + u32 field_sepol2; + u32 field_sepol3; + u32 field_sepol4; + u32 field_sepol5; + u32 field_sepol6; + u32 field_sepol7; }; static int get_object(char *buf, char __user *user_object, size_t buf_sz, - char **object) + char **object) { - if (!user_object) { - *object = ALL; - return 0; - } + if (!user_object) { + *object = ALL; + return 0; + } - if (strncpy_from_user(buf, user_object, buf_sz) < 0) { - return -1; - } + if (strncpy_from_user(buf, user_object, buf_sz) < 0) { + return -1; + } - *object = buf; + *object = buf; - return 0; + return 0; } // 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) || \ - !defined(KSU_COMPAT_USE_SELINUX_STATE) - avc_ss_reset(0); - selnl_notify_policyload(0); - selinux_status_update_policyload(0); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \ + !defined(KSU_COMPAT_USE_SELINUX_STATE) + avc_ss_reset(0); + selnl_notify_policyload(0); + selinux_status_update_policyload(0); #else - struct selinux_avc *avc = selinux_state.avc; - avc_ss_reset(avc, 0); - selnl_notify_policyload(0); - selinux_status_update_policyload(&selinux_state, 0); + struct selinux_avc *avc = selinux_state.avc; + avc_ss_reset(avc, 0); + selnl_notify_policyload(0); + selinux_status_update_policyload(&selinux_state, 0); #endif - selinux_xfrm_notify_policyload(); + selinux_xfrm_notify_policyload(); } int handle_sepolicy(unsigned long arg3, void __user *arg4) { - struct policydb *db; + struct policydb *db; - if (!arg4) { - return -1; - } + if (!arg4) { + return -1; + } - if (!getenforce()) { - pr_info("SELinux permissive or disabled when handle policy!\n"); - } + if (!getenforce()) { + pr_info("SELinux permissive or disabled when handle policy!\n"); + } - u32 cmd, subcmd; - char __user *sepol1, *sepol2, *sepol3, *sepol4, *sepol5, *sepol6, *sepol7; + u32 cmd, subcmd; + char __user *sepol1, *sepol2, *sepol3, *sepol4, *sepol5, *sepol6, *sepol7; - if (unlikely(ksu_is_compat)) { - struct sepol_data_compat data_compat; - if (copy_from_user(&data_compat, arg4, sizeof(struct sepol_data_compat))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - pr_info("sepol: running in compat mode!\n"); - sepol1 = compat_ptr(data_compat.field_sepol1); - sepol2 = compat_ptr(data_compat.field_sepol2); - sepol3 = compat_ptr(data_compat.field_sepol3); - sepol4 = compat_ptr(data_compat.field_sepol4); - sepol5 = compat_ptr(data_compat.field_sepol5); - sepol6 = compat_ptr(data_compat.field_sepol6); - sepol7 = compat_ptr(data_compat.field_sepol7); - cmd = data_compat.cmd; - subcmd = data_compat.subcmd; - } else { - struct sepol_data data; - if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - sepol1 = data.field_sepol1; - sepol2 = data.field_sepol2; - sepol3 = data.field_sepol3; - sepol4 = data.field_sepol4; - sepol5 = data.field_sepol5; - sepol6 = data.field_sepol6; - sepol7 = data.field_sepol7; - cmd = data.cmd; - subcmd = data.subcmd; - } + if (unlikely(ksu_is_compat)) { + struct sepol_data_compat data_compat; + if (copy_from_user(&data_compat, arg4, sizeof(struct sepol_data_compat))) { + pr_err("sepol: copy sepol_data failed.\n"); + return -1; + } + pr_info("sepol: running in compat mode!\n"); + sepol1 = compat_ptr(data_compat.field_sepol1); + sepol2 = compat_ptr(data_compat.field_sepol2); + sepol3 = compat_ptr(data_compat.field_sepol3); + sepol4 = compat_ptr(data_compat.field_sepol4); + sepol5 = compat_ptr(data_compat.field_sepol5); + sepol6 = compat_ptr(data_compat.field_sepol6); + sepol7 = compat_ptr(data_compat.field_sepol7); + cmd = data_compat.cmd; + subcmd = data_compat.subcmd; + } else { + struct sepol_data data; + if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { + pr_err("sepol: copy sepol_data failed.\n"); + return -1; + } + sepol1 = data.field_sepol1; + sepol2 = data.field_sepol2; + sepol3 = data.field_sepol3; + sepol4 = data.field_sepol4; + sepol5 = data.field_sepol5; + sepol6 = data.field_sepol6; + sepol7 = data.field_sepol7; + cmd = data.cmd; + subcmd = data.subcmd; + } - mutex_lock(&ksu_rules); + mutex_lock(&ksu_rules); - db = get_policydb(); + db = get_policydb(); - int ret = -1; - if (cmd == CMD_NORMAL_PERM) { - char src_buf[MAX_SEPOL_LEN]; - char tgt_buf[MAX_SEPOL_LEN]; - char cls_buf[MAX_SEPOL_LEN]; - char perm_buf[MAX_SEPOL_LEN]; + int ret = -1; + if (cmd == CMD_NORMAL_PERM) { + char src_buf[MAX_SEPOL_LEN]; + char tgt_buf[MAX_SEPOL_LEN]; + char cls_buf[MAX_SEPOL_LEN]; + char perm_buf[MAX_SEPOL_LEN]; - char *s, *t, *c, *p; - if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } + char *s, *t, *c, *p; + if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } - if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } + if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } - if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } + if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } - if (get_object(perm_buf, sepol4, sizeof(perm_buf), &p) < - 0) { - pr_err("sepol: copy perm failed.\n"); - goto exit; - } + if (get_object(perm_buf, sepol4, sizeof(perm_buf), &p) < + 0) { + pr_err("sepol: copy perm failed.\n"); + goto exit; + } - bool success = false; - if (subcmd == 1) { - success = ksu_allow(db, s, t, c, p); - } else if (subcmd == 2) { - success = ksu_deny(db, s, t, c, p); - } else if (subcmd == 3) { - success = ksu_auditallow(db, s, t, c, p); - } else if (subcmd == 4) { - success = ksu_dontaudit(db, s, t, c, p); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - ret = success ? 0 : -1; + bool success = false; + if (subcmd == 1) { + success = ksu_allow(db, s, t, c, p); + } else if (subcmd == 2) { + success = ksu_deny(db, s, t, c, p); + } else if (subcmd == 3) { + success = ksu_auditallow(db, s, t, c, p); + } else if (subcmd == 4) { + success = ksu_dontaudit(db, s, t, c, p); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + ret = success ? 0 : -1; - } else if (cmd == CMD_XPERM) { - char src_buf[MAX_SEPOL_LEN]; - char tgt_buf[MAX_SEPOL_LEN]; - char cls_buf[MAX_SEPOL_LEN]; + } else if (cmd == CMD_XPERM) { + char src_buf[MAX_SEPOL_LEN]; + char tgt_buf[MAX_SEPOL_LEN]; + char cls_buf[MAX_SEPOL_LEN]; - char __maybe_unused - operation[MAX_SEPOL_LEN]; // it is always ioctl now! - char perm_set[MAX_SEPOL_LEN]; + char __maybe_unused + operation[MAX_SEPOL_LEN]; // it is always ioctl now! + char perm_set[MAX_SEPOL_LEN]; - char *s, *t, *c; - if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(operation, sepol4, - sizeof(operation)) < 0) { - pr_err("sepol: copy operation failed.\n"); - goto exit; - } - if (strncpy_from_user(perm_set, sepol5, sizeof(perm_set)) < - 0) { - pr_err("sepol: copy perm_set failed.\n"); - goto exit; - } + char *s, *t, *c; + if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } + if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } + if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } + if (strncpy_from_user(operation, sepol4, + sizeof(operation)) < 0) { + pr_err("sepol: copy operation failed.\n"); + goto exit; + } + if (strncpy_from_user(perm_set, sepol5, sizeof(perm_set)) < + 0) { + pr_err("sepol: copy perm_set failed.\n"); + goto exit; + } - bool success = false; - if (subcmd == 1) { - success = ksu_allowxperm(db, s, t, c, perm_set); - } else if (subcmd == 2) { - success = ksu_auditallowxperm(db, s, t, c, perm_set); - } else if (subcmd == 3) { - success = ksu_dontauditxperm(db, s, t, c, perm_set); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - ret = success ? 0 : -1; - } else if (cmd == CMD_TYPE_STATE) { - char src[MAX_SEPOL_LEN]; + bool success = false; + if (subcmd == 1) { + success = ksu_allowxperm(db, s, t, c, perm_set); + } else if (subcmd == 2) { + success = ksu_auditallowxperm(db, s, t, c, perm_set); + } else if (subcmd == 3) { + success = ksu_dontauditxperm(db, s, t, c, perm_set); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + ret = success ? 0 : -1; + } else if (cmd == CMD_TYPE_STATE) { + char src[MAX_SEPOL_LEN]; - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } + if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } - bool success = false; - if (subcmd == 1) { - success = ksu_permissive(db, src); - } else if (subcmd == 2) { - success = ksu_enforce(db, src); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - if (success) - ret = 0; + bool success = false; + if (subcmd == 1) { + success = ksu_permissive(db, src); + } else if (subcmd == 2) { + success = ksu_enforce(db, src); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + if (success) + ret = 0; - } else if (cmd == CMD_TYPE || cmd == CMD_TYPE_ATTR) { - char type[MAX_SEPOL_LEN]; - char attr[MAX_SEPOL_LEN]; + } else if (cmd == CMD_TYPE || cmd == CMD_TYPE_ATTR) { + char type[MAX_SEPOL_LEN]; + char attr[MAX_SEPOL_LEN]; - if (strncpy_from_user(type, sepol1, sizeof(type)) < 0) { - pr_err("sepol: copy type failed.\n"); - goto exit; - } - if (strncpy_from_user(attr, sepol2, sizeof(attr)) < 0) { - pr_err("sepol: copy attr failed.\n"); - goto exit; - } + if (strncpy_from_user(type, sepol1, sizeof(type)) < 0) { + pr_err("sepol: copy type failed.\n"); + goto exit; + } + if (strncpy_from_user(attr, sepol2, sizeof(attr)) < 0) { + pr_err("sepol: copy attr failed.\n"); + goto exit; + } - bool success = false; - if (cmd == CMD_TYPE) { - success = ksu_type(db, type, attr); - } else { - success = ksu_typeattribute(db, type, attr); - } - if (!success) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; + bool success = false; + if (cmd == CMD_TYPE) { + success = ksu_type(db, type, attr); + } else { + success = ksu_typeattribute(db, type, attr); + } + if (!success) { + pr_err("sepol: %d failed.\n", cmd); + goto exit; + } + ret = 0; - } else if (cmd == CMD_ATTR) { - char attr[MAX_SEPOL_LEN]; + } else if (cmd == CMD_ATTR) { + char attr[MAX_SEPOL_LEN]; - if (strncpy_from_user(attr, sepol1, sizeof(attr)) < 0) { - pr_err("sepol: copy attr failed.\n"); - goto exit; - } - if (!ksu_attribute(db, attr)) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; + if (strncpy_from_user(attr, sepol1, sizeof(attr)) < 0) { + pr_err("sepol: copy attr failed.\n"); + goto exit; + } + if (!ksu_attribute(db, attr)) { + pr_err("sepol: %d failed.\n", cmd); + goto exit; + } + ret = 0; - } else if (cmd == CMD_TYPE_TRANSITION) { - char src[MAX_SEPOL_LEN]; - char tgt[MAX_SEPOL_LEN]; - char cls[MAX_SEPOL_LEN]; - char default_type[MAX_SEPOL_LEN]; - char object[MAX_SEPOL_LEN]; + } else if (cmd == CMD_TYPE_TRANSITION) { + char src[MAX_SEPOL_LEN]; + char tgt[MAX_SEPOL_LEN]; + char cls[MAX_SEPOL_LEN]; + char default_type[MAX_SEPOL_LEN]; + char object[MAX_SEPOL_LEN]; - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(default_type, sepol4, - sizeof(default_type)) < 0) { - pr_err("sepol: copy default_type failed.\n"); - goto exit; - } - char *real_object; - if (sepol5 == NULL) { - real_object = NULL; - } else { - if (strncpy_from_user(object, sepol5, - sizeof(object)) < 0) { - pr_err("sepol: copy object failed.\n"); - goto exit; - } - real_object = object; - } + if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } + if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } + if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } + if (strncpy_from_user(default_type, sepol4, + sizeof(default_type)) < 0) { + pr_err("sepol: copy default_type failed.\n"); + goto exit; + } + char *real_object; + if (sepol5 == NULL) { + real_object = NULL; + } else { + if (strncpy_from_user(object, sepol5, + sizeof(object)) < 0) { + pr_err("sepol: copy object failed.\n"); + goto exit; + } + real_object = object; + } - bool success = ksu_type_transition(db, src, tgt, cls, - default_type, real_object); - if (success) - ret = 0; + bool success = ksu_type_transition(db, src, tgt, cls, + default_type, real_object); + if (success) + ret = 0; - } else if (cmd == CMD_TYPE_CHANGE) { - char src[MAX_SEPOL_LEN]; - char tgt[MAX_SEPOL_LEN]; - char cls[MAX_SEPOL_LEN]; - char default_type[MAX_SEPOL_LEN]; + } else if (cmd == CMD_TYPE_CHANGE) { + char src[MAX_SEPOL_LEN]; + char tgt[MAX_SEPOL_LEN]; + char cls[MAX_SEPOL_LEN]; + char default_type[MAX_SEPOL_LEN]; - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(default_type, sepol4, - sizeof(default_type)) < 0) { - pr_err("sepol: copy default_type failed.\n"); - goto exit; - } - bool success = false; - if (subcmd == 1) { - success = ksu_type_change(db, src, tgt, cls, - default_type); - } else if (subcmd == 2) { - success = ksu_type_member(db, src, tgt, cls, - default_type); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - if (success) - ret = 0; - } else if (cmd == CMD_GENFSCON) { - char name[MAX_SEPOL_LEN]; - char path[MAX_SEPOL_LEN]; - char context[MAX_SEPOL_LEN]; - if (strncpy_from_user(name, sepol1, sizeof(name)) < 0) { - pr_err("sepol: copy name failed.\n"); - goto exit; - } - if (strncpy_from_user(path, sepol2, sizeof(path)) < 0) { - pr_err("sepol: copy path failed.\n"); - goto exit; - } - if (strncpy_from_user(context, sepol3, sizeof(context)) < - 0) { - pr_err("sepol: copy context failed.\n"); - goto exit; - } + if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { + pr_err("sepol: copy src failed.\n"); + goto exit; + } + if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { + pr_err("sepol: copy tgt failed.\n"); + goto exit; + } + if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { + pr_err("sepol: copy cls failed.\n"); + goto exit; + } + if (strncpy_from_user(default_type, sepol4, + sizeof(default_type)) < 0) { + pr_err("sepol: copy default_type failed.\n"); + goto exit; + } + bool success = false; + if (subcmd == 1) { + success = ksu_type_change(db, src, tgt, cls, + default_type); + } else if (subcmd == 2) { + success = ksu_type_member(db, src, tgt, cls, + default_type); + } else { + pr_err("sepol: unknown subcmd: %d\n", subcmd); + } + if (success) + ret = 0; + } else if (cmd == CMD_GENFSCON) { + char name[MAX_SEPOL_LEN]; + char path[MAX_SEPOL_LEN]; + char context[MAX_SEPOL_LEN]; + if (strncpy_from_user(name, sepol1, sizeof(name)) < 0) { + pr_err("sepol: copy name failed.\n"); + goto exit; + } + if (strncpy_from_user(path, sepol2, sizeof(path)) < 0) { + pr_err("sepol: copy path failed.\n"); + goto exit; + } + if (strncpy_from_user(context, sepol3, sizeof(context)) < + 0) { + pr_err("sepol: copy context failed.\n"); + goto exit; + } - if (!ksu_genfscon(db, name, path, context)) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - } else { - pr_err("sepol: unknown cmd: %d\n", cmd); - } + if (!ksu_genfscon(db, name, path, context)) { + pr_err("sepol: %d failed.\n", cmd); + goto exit; + } + ret = 0; + } else { + pr_err("sepol: unknown cmd: %d\n", cmd); + } exit: - mutex_unlock(&ksu_rules); + mutex_unlock(&ksu_rules); - // only allow and xallow needs to reset avc cache, but we cannot do that because - // we are in atomic context. so we just reset it every time. - reset_avc_cache(); + // only allow and xallow needs to reset avc cache, but we cannot do that because + // we are in atomic context. so we just reset it every time. + reset_avc_cache(); - return ret; + return ret; } diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 2637f57e..10cee518 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -16,232 +16,232 @@ u32 susfs_kernel_sid = 0; static int transive_to_domain(const char *domain) { - struct cred *cred; - struct task_security_struct *tsec; - u32 sid; - int error; + struct cred *cred; + struct task_security_struct *tsec; + u32 sid; + int error; - cred = (struct cred *)__task_cred(current); + cred = (struct cred *)__task_cred(current); - tsec = cred->security; - if (!tsec) { - pr_err("tsec == NULL!\n"); - return -1; - } + tsec = cred->security; + if (!tsec) { + pr_err("tsec == NULL!\n"); + return -1; + } - error = security_secctx_to_secid(domain, strlen(domain), &sid); - if (error) { - pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", - domain, sid, error); - } + error = security_secctx_to_secid(domain, strlen(domain), &sid); + if (error) { + pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", + domain, sid, error); + } - if (!error) { - tsec->sid = sid; - tsec->create_sid = 0; - tsec->keycreate_sid = 0; - tsec->sockcreate_sid = 0; - } + if (!error) { + tsec->sid = sid; + tsec->create_sid = 0; + tsec->keycreate_sid = 0; + tsec->sockcreate_sid = 0; + } - return error; + return error; } #if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0) bool __maybe_unused is_ksu_transition(const struct task_security_struct *old_tsec, - const struct task_security_struct *new_tsec) + const struct task_security_struct *new_tsec) { - static u32 ksu_sid; - char *secdata; - u32 seclen; - bool allowed = false; + static u32 ksu_sid; + char *secdata; + u32 seclen; + bool allowed = false; - if (!ksu_sid) - security_secctx_to_secid(KERNEL_SU_DOMAIN, strlen(KERNEL_SU_DOMAIN), &ksu_sid); + if (!ksu_sid) + security_secctx_to_secid(KERNEL_SU_DOMAIN, strlen(KERNEL_SU_DOMAIN), &ksu_sid); - if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen)) - return false; + if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen)) + return false; - allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid); - security_release_secctx(secdata, seclen); - return allowed; + allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid); + security_release_secctx(secdata, seclen); + return allowed; } #endif void setup_selinux(const char *domain) { - if (transive_to_domain(domain)) { - pr_err("transive domain failed.\n"); - return; - } + if (transive_to_domain(domain)) { + pr_err("transive domain failed.\n"); + return; + } } void setenforce(bool enforce) { - __setenforce(enforce); + __setenforce(enforce); } bool getenforce(void) { - if (is_selinux_disabled()) { - return false; - } + if (is_selinux_disabled()) { + return false; + } - return __is_selinux_enforcing(); + return __is_selinux_enforcing(); } #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \ - !defined(KSU_COMPAT_HAS_CURRENT_SID) + !defined(KSU_COMPAT_HAS_CURRENT_SID) /* * get the subjective security ID of the current task */ static inline u32 current_sid(void) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = current_security(); - return tsec->sid; + return tsec->sid; } #endif bool is_ksu_domain(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - struct lsm_context ctx; + struct lsm_context ctx; #else - char *domain; - u32 seclen; + char *domain; + u32 seclen; #endif - bool result; + bool result; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - int err = security_secid_to_secctx(current_sid(), &ctx); + int err = security_secid_to_secctx(current_sid(), &ctx); #else - int err = security_secid_to_secctx(current_sid(), &domain, &seclen); + int err = security_secid_to_secctx(current_sid(), &domain, &seclen); #endif - if (err) { - return false; - } + if (err) { + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0; - security_release_secctx(&ctx); + result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0; + security_release_secctx(&ctx); #else - result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0; - security_release_secctx(domain, seclen); + result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0; + security_release_secctx(domain, seclen); #endif - return result; + return result; } bool is_zygote(void *sec) { - struct task_security_struct *tsec = (struct task_security_struct *)sec; - if (!tsec) { - return false; - } + struct task_security_struct *tsec = (struct task_security_struct *)sec; + if (!tsec) { + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - struct lsm_context ctx; + struct lsm_context ctx; #else - char *domain; - u32 seclen; + char *domain; + u32 seclen; #endif - bool result; + bool result; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - int err = security_secid_to_secctx(tsec->sid, &ctx); + int err = security_secid_to_secctx(tsec->sid, &ctx); #else - int err = security_secid_to_secctx(tsec->sid, &domain, &seclen); + int err = security_secid_to_secctx(tsec->sid, &domain, &seclen); #endif - if (err) { - return false; - } + if (err) { + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - result = strncmp("u:r:zygote:s0", ctx.context, ctx.len) == 0; - security_release_secctx(&ctx); + result = strncmp("u:r:zygote:s0", ctx.context, ctx.len) == 0; + security_release_secctx(&ctx); #else - result = strncmp("u:r:zygote:s0", domain, seclen) == 0; - security_release_secctx(domain, seclen); + result = strncmp("u:r:zygote:s0", domain, seclen) == 0; + security_release_secctx(domain, seclen); #endif - return result; + return result; } #ifdef CONFIG_KSU_SUSFS 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_kernel_sid(void) { - susfs_set_sid(KERNEL_KERNEL_DOMAIN, &susfs_kernel_sid); + susfs_set_sid(KERNEL_KERNEL_DOMAIN, &susfs_kernel_sid); } #endif @@ -249,12 +249,12 @@ void susfs_set_kernel_sid(void) u32 ksu_get_devpts_sid(void) { - u32 devpts_sid = 0; - int err = security_secctx_to_secid(DEVPTS_DOMAIN, strlen(DEVPTS_DOMAIN), - &devpts_sid); + u32 devpts_sid = 0; + int err = security_secctx_to_secid(DEVPTS_DOMAIN, strlen(DEVPTS_DOMAIN), + &devpts_sid); - if (err) - pr_info("get devpts sid err %d\n", err); + if (err) + pr_info("get devpts sid err %d\n", err); - return devpts_sid; + return devpts_sid; } diff --git a/kernel/selinux/selinux_defs.h b/kernel/selinux/selinux_defs.h index 391da8ad..bdd41b77 100644 --- a/kernel/selinux/selinux_defs.h +++ b/kernel/selinux/selinux_defs.h @@ -12,24 +12,24 @@ #ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef KSU_COMPAT_USE_SELINUX_STATE -#define is_selinux_disabled() (selinux_state.disabled) +#define is_selinux_disabled() (selinux_state.disabled) #else -#define is_selinux_disabled() (selinux_disabled) +#define is_selinux_disabled() (selinux_disabled) #endif #else -#define is_selinux_disabled() (0) +#define is_selinux_disabled() (0) #endif #ifdef CONFIG_SECURITY_SELINUX_DEVELOP #ifdef KSU_COMPAT_USE_SELINUX_STATE -#define __is_selinux_enforcing() (selinux_state.enforcing) -#define __setenforce(val) selinux_state.enforcing = val +#define __is_selinux_enforcing() (selinux_state.enforcing) +#define __setenforce(val) selinux_state.enforcing = val #elif defined(SAMSUNG_SELINUX_PORTING) || !defined(KSU_COMPAT_USE_SELINUX_STATE) -#define __is_selinux_enforcing() (selinux_enforcing) -#define __setenforce(val) selinux_enforcing = val +#define __is_selinux_enforcing() (selinux_enforcing) +#define __setenforce(val) selinux_enforcing = val #endif #else -#define __is_selinux_enforcing() (1) +#define __is_selinux_enforcing() (1) #define __setenforce(val) #endif diff --git a/kernel/selinux/sepolicy.c b/kernel/selinux/sepolicy.c index 08831038..a1d7334f 100644 --- a/kernel/selinux/sepolicy.c +++ b/kernel/selinux/sepolicy.c @@ -15,44 +15,44 @@ ////////////////////////////////////////////////////// static struct avtab_node *get_avtab_node(struct policydb *db, - struct avtab_key *key, - struct avtab_extended_perms *xperms); + struct avtab_key *key, + 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); + 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); + const char *c, const char *range, int effect, + bool invert); static bool add_type_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *d, int effect); + 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); + const char *path, const char *context); static bool add_type(struct policydb *db, const char *type_name, bool attr); static bool set_type_state(struct policydb *db, const char *type_name, - bool permissive); + bool permissive); static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, - struct type_datum *attr); + struct type_datum *attr); static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr); + const char *attr); ////////////////////////////////////////////////////// // Implementation @@ -63,18 +63,18 @@ static bool add_typeattribute(struct policydb *db, const char *type, #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) \ - for (cur = node_ptr[i]; cur; cur = cur->next) + 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) \ - ksu_hash_for_each(htab.htable, htab.size, cur) + ksu_hash_for_each(htab.htable, htab.size, cur) #else #define ksu_hashtab_for_each(htab, cur) \ - ksu_hash_for_each(htab->htable, htab->size, cur) + ksu_hash_for_each(htab->htable, htab->size, cur) #endif // symtab_search is introduced on 5.9.0: @@ -85,186 +85,186 @@ static bool add_typeattribute(struct policydb *db, const char *type, #endif #define avtab_for_each(avtab, cur) \ - ksu_hash_for_each(avtab.htable, avtab.nslot, cur); + ksu_hash_for_each(avtab.htable, avtab.nslot, cur); static struct avtab_node *get_avtab_node(struct policydb *db, - struct avtab_key *key, - struct avtab_extended_perms *xperms) + struct avtab_key *key, + struct avtab_extended_perms *xperms) { - struct avtab_node *node; + struct avtab_node *node; - /* AVTAB_XPERMS entries are not necessarily unique */ - if (key->specified & AVTAB_XPERMS) { - bool match = false; - 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)) { - match = true; - break; - } - node = avtab_search_node_next(node, key->specified); - } - if (!match) - node = NULL; - } else { - node = avtab_search_node(&db->te_avtab, key); - } + /* AVTAB_XPERMS entries are not necessarily unique */ + if (key->specified & AVTAB_XPERMS) { + bool match = false; + 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)) { + match = true; + break; + } + node = avtab_search_node_next(node, key->specified); + } + if (!match) + node = NULL; + } else { + node = avtab_search_node(&db->te_avtab, key); + } - if (!node) { - struct avtab_datum avdatum = {}; - /* + if (!node) { + struct avtab_datum avdatum = {}; + /* * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for * others. Initialize the data accordingly. */ - if (key->specified & AVTAB_XPERMS) { - avdatum.u.xperms = xperms; - } else { - avdatum.u.data = - key->specified == AVTAB_AUDITDENY ? ~0U : 0U; - } - /* this is used to get the node - insertion is actually unique */ - node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); + if (key->specified & AVTAB_XPERMS) { + avdatum.u.xperms = xperms; + } else { + avdatum.u.data = + key->specified == AVTAB_AUDITDENY ? ~0U : 0U; + } + /* this is used to get the node - insertion is actually unique */ + node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); - int grow_size = sizeof(struct avtab_key); - grow_size += sizeof(struct avtab_datum); - if (key->specified & AVTAB_XPERMS) { - grow_size += sizeof(u8); - grow_size += sizeof(u8); - grow_size += sizeof(u32) * - ARRAY_SIZE(avdatum.u.xperms->perms.p); - } - db->len += grow_size; - } + int grow_size = sizeof(struct avtab_key); + grow_size += sizeof(struct avtab_datum); + if (key->specified & AVTAB_XPERMS) { + grow_size += sizeof(u8); + grow_size += sizeof(u8); + grow_size += sizeof(u32) * + ARRAY_SIZE(avdatum.u.xperms->perms.p); + } + db->len += grow_size; + } - return node; + return node; } 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; - struct perm_datum *perm = NULL; + struct type_datum *src = NULL, *tgt = NULL; + struct class_datum *cls = NULL; + struct perm_datum *perm = NULL; - if (s) { - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - } + if (s) { + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + } - if (t) { - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - } + if (t) { + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + } - if (c) { - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - } + if (c) { + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + } - if (p) { - if (c == NULL) { - pr_info("No class is specified, cannot add perm [%s] \n", - p); - return false; - } + if (p) { + if (c == NULL) { + pr_info("No class is specified, cannot add perm [%s] \n", + p); + return false; + } - perm = symtab_search(&cls->permissions, p); - if (perm == NULL && cls->comdatum != NULL) { - perm = symtab_search(&cls->comdatum->permissions, p); - } - if (perm == NULL) { - pr_info("perm %s does not exist in class %s\n", p, c); - return false; - } - } - add_rule_raw(db, src, tgt, cls, perm, effect, invert); - return true; + perm = symtab_search(&cls->permissions, p); + if (perm == NULL && cls->comdatum != NULL) { + perm = symtab_search(&cls->comdatum->permissions, p); + } + if (perm == NULL) { + pr_info("perm %s does not exist in class %s\n", p, c); + return false; + } + } + add_rule_raw(db, src, tgt, cls, perm, effect, invert); + return true; } 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) + struct type_datum *tgt, struct class_datum *cls, + struct perm_datum *perm, int effect, bool invert) { - if (src == NULL) { - struct hashtab_node *node; - if (strip_av(effect, invert)) { - ksu_hashtab_for_each(db->p_types.table, node) - { - add_rule_raw(db, - (struct type_datum *)node->datum, - tgt, cls, perm, effect, invert); - }; - } else { - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_rule_raw(db, type, tgt, cls, perm, - effect, invert); - } - }; - } - } else if (tgt == NULL) { - struct hashtab_node *node; - if (strip_av(effect, invert)) { - ksu_hashtab_for_each(db->p_types.table, node) - { - add_rule_raw(db, src, - (struct type_datum *)node->datum, - cls, perm, effect, invert); - }; - } else { - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_rule_raw(db, src, type, cls, perm, - effect, invert); - } - }; - } - } else if (cls == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_classes.table, node) - { - add_rule_raw(db, src, tgt, - (struct class_datum *)node->datum, perm, - effect, invert); - } - } else { - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; + if (src == NULL) { + struct hashtab_node *node; + if (strip_av(effect, invert)) { + ksu_hashtab_for_each(db->p_types.table, node) + { + add_rule_raw(db, + (struct type_datum *)node->datum, + tgt, cls, perm, effect, invert); + }; + } else { + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_rule_raw(db, type, tgt, cls, perm, + effect, invert); + } + }; + } + } else if (tgt == NULL) { + struct hashtab_node *node; + if (strip_av(effect, invert)) { + ksu_hashtab_for_each(db->p_types.table, node) + { + add_rule_raw(db, src, + (struct type_datum *)node->datum, + cls, perm, effect, invert); + }; + } else { + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_rule_raw(db, src, type, cls, perm, + effect, invert); + } + }; + } + } else if (cls == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_classes.table, node) + { + add_rule_raw(db, src, tgt, + (struct class_datum *)node->datum, perm, + effect, invert); + } + } else { + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; - struct avtab_node *node = get_avtab_node(db, &key, NULL); - if (invert) { - if (perm) - node->datum.u.data &= - ~(1U << (perm->value - 1)); - else - node->datum.u.data = 0U; - } else { - if (perm) - node->datum.u.data |= 1U << (perm->value - 1); - else - node->datum.u.data = ~0U; - } - } + struct avtab_node *node = get_avtab_node(db, &key, NULL); + if (invert) { + if (perm) + node->datum.u.data &= + ~(1U << (perm->value - 1)); + else + node->datum.u.data = 0U; + } else { + if (perm) + node->datum.u.data |= 1U << (perm->value - 1); + else + node->datum.u.data = ~0U; + } + } } #define ioctl_driver(x) (x >> 8 & 0xFF) @@ -275,183 +275,183 @@ 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; - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_xperm_rule_raw(db, type, tgt, cls, low, - high, effect, invert); - } - }; - } else if (tgt == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_xperm_rule_raw(db, src, type, cls, low, - high, effect, invert); - } - }; - } else if (cls == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_classes.table, node) - { - add_xperm_rule_raw(db, src, tgt, - (struct class_datum *)(node->datum), - low, high, effect, invert); - }; - } else { - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; + if (src == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_xperm_rule_raw(db, type, tgt, cls, low, + high, effect, invert); + } + }; + } else if (tgt == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_types.table, node) + { + struct type_datum *type = + (struct type_datum *)(node->datum); + if (type->attribute) { + add_xperm_rule_raw(db, src, type, cls, low, + high, effect, invert); + } + }; + } else if (cls == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_classes.table, node) + { + add_xperm_rule_raw(db, src, tgt, + (struct class_datum *)(node->datum), + low, high, effect, invert); + }; + } else { + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; - struct avtab_datum *datum; - struct avtab_node *node; - struct avtab_extended_perms xperms; + struct avtab_datum *datum; + struct avtab_node *node; + struct avtab_extended_perms xperms; - memset(&xperms, 0, sizeof(xperms)); - if (ioctl_driver(low) != ioctl_driver(high)) { - xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; - xperms.driver = 0; - } else { - xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; - xperms.driver = ioctl_driver(low); - } - int i; - if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { - for (i = ioctl_driver(low); i <= ioctl_driver(high); - ++i) { - if (invert) - xperm_clear(i, xperms.perms.p); - else - xperm_set(i, xperms.perms.p); - } - } else { - for (i = ioctl_func(low); i <= ioctl_func(high); ++i) { - if (invert) - xperm_clear(i, xperms.perms.p); - else - xperm_set(i, xperms.perms.p); - } - } + memset(&xperms, 0, sizeof(xperms)); + if (ioctl_driver(low) != ioctl_driver(high)) { + xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + xperms.driver = 0; + } else { + xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; + xperms.driver = ioctl_driver(low); + } + int i; + if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { + for (i = ioctl_driver(low); i <= ioctl_driver(high); + ++i) { + if (invert) + xperm_clear(i, xperms.perms.p); + else + xperm_set(i, xperms.perms.p); + } + } else { + for (i = ioctl_func(low); i <= ioctl_func(high); ++i) { + if (invert) + xperm_clear(i, xperms.perms.p); + else + xperm_set(i, xperms.perms.p); + } + } - node = get_avtab_node(db, &key, &xperms); - if (!node) { - pr_warn("add_xperm_rule_raw cannot found node!\n"); - return; - } - datum = &node->datum; + node = get_avtab_node(db, &key, &xperms); + if (!node) { + pr_warn("add_xperm_rule_raw cannot found node!\n"); + return; + } + datum = &node->datum; - if (datum->u.xperms == NULL) { - datum->u.xperms = - (struct avtab_extended_perms *)(kmalloc( - sizeof(xperms), GFP_KERNEL)); - if (!datum->u.xperms) { - pr_err("alloc xperms failed\n"); - return; - } - memcpy(datum->u.xperms, &xperms, sizeof(xperms)); - } - } + if (datum->u.xperms == NULL) { + datum->u.xperms = + (struct avtab_extended_perms *)(kmalloc( + sizeof(xperms), GFP_KERNEL)); + if (!datum->u.xperms) { + pr_err("alloc xperms failed\n"); + return; + } + memcpy(datum->u.xperms, &xperms, sizeof(xperms)); + } + } } static bool add_xperm_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *range, int effect, - bool invert) + const char *c, const char *range, int effect, + bool invert) { - struct type_datum *src = NULL, *tgt = NULL; - struct class_datum *cls = NULL; + struct type_datum *src = NULL, *tgt = NULL; + struct class_datum *cls = NULL; - if (s) { - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - } + if (s) { + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + } - if (t) { - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - } + if (t) { + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + } - if (c) { - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - } + if (c) { + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + } - u16 low, high; + u16 low, high; - if (range) { - if (strchr(range, '-')) { - sscanf(range, "%hx-%hx", &low, &high); - } else { - sscanf(range, "%hx", &low); - high = low; - } - } else { - low = 0; - high = 0xFFFF; - } + if (range) { + if (strchr(range, '-')) { + sscanf(range, "%hx-%hx", &low, &high); + } else { + sscanf(range, "%hx", &low); + high = low; + } + } else { + low = 0; + high = 0xFFFF; + } - add_xperm_rule_raw(db, src, tgt, cls, low, high, effect, invert); - return true; + add_xperm_rule_raw(db, src, tgt, cls, low, high, effect, invert); + return true; } static bool add_type_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *d, int effect) + const char *c, const char *d, int effect) { - struct type_datum *src, *tgt, *def; - struct class_datum *cls; + struct type_datum *src, *tgt, *def; + struct class_datum *cls; - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - def = symtab_search(&db->p_types, d); - if (def == NULL) { - pr_info("default type %s does not exist\n", d); - return false; - } + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_info("source type %s does not exist\n", s); + return false; + } + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_info("target type %s does not exist\n", t); + return false; + } + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_info("class %s does not exist\n", c); + return false; + } + def = symtab_search(&db->p_types, d); + if (def == NULL) { + pr_info("default type %s does not exist\n", d); + return false; + } - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; + struct avtab_key key; + key.source_type = src->value; + key.target_type = tgt->value; + key.target_class = cls->value; + key.specified = effect; - struct avtab_node *node = get_avtab_node(db, &key, NULL); - node->datum.u.data = def->value; + struct avtab_node *node = get_avtab_node(db, &key, NULL); + node->datum.u.data = def->value; - return true; + return true; } // 5.9.0 : static inline int hashtab_insert(struct hashtab *h, void *key, void @@ -460,504 +460,504 @@ static bool add_type_rule(struct policydb *db, const char *s, const char *t, #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) static u32 filenametr_hash(const void *k) { - const struct filename_trans_key *ft = k; - unsigned long hash; - unsigned int byte_num; - unsigned char focus; + const struct filename_trans_key *ft = k; + unsigned long hash; + unsigned int byte_num; + unsigned char focus; - hash = ft->ttype ^ ft->tclass; + hash = ft->ttype ^ ft->tclass; - byte_num = 0; - while ((focus = ft->name[byte_num++])) - hash = partial_name_hash(focus, hash); - return hash; + byte_num = 0; + while ((focus = ft->name[byte_num++])) + hash = partial_name_hash(focus, hash); + return hash; } static int filenametr_cmp(const void *k1, const void *k2) { - const struct filename_trans_key *ft1 = k1; - const struct filename_trans_key *ft2 = k2; - int v; + const struct filename_trans_key *ft1 = k1; + const struct filename_trans_key *ft2 = k2; + int v; - v = ft1->ttype - ft2->ttype; - if (v) - return v; + v = ft1->ttype - ft2->ttype; + if (v) + return v; - v = ft1->tclass - ft2->tclass; - if (v) - return v; + v = ft1->tclass - ft2->tclass; + if (v) + return v; - return strcmp(ft1->name, ft2->name); + return strcmp(ft1->name, ft2->name); } static const struct hashtab_key_params filenametr_key_params = { - .hash = filenametr_hash, - .cmp = filenametr_cmp, + .hash = filenametr_hash, + .cmp = filenametr_cmp, }; #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; + struct type_datum *src, *tgt, *def; + struct class_datum *cls; - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_warn("source type %s does not exist\n", s); - return false; - } - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_warn("target type %s does not exist\n", t); - return false; - } - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_warn("class %s does not exist\n", c); - return false; - } - def = symtab_search(&db->p_types, d); - if (def == NULL) { - pr_warn("default type %s does not exist\n", d); - return false; - } + src = symtab_search(&db->p_types, s); + if (src == NULL) { + pr_warn("source type %s does not exist\n", s); + return false; + } + tgt = symtab_search(&db->p_types, t); + if (tgt == NULL) { + pr_warn("target type %s does not exist\n", t); + return false; + } + cls = symtab_search(&db->p_classes, c); + if (cls == NULL) { + pr_warn("class %s does not exist\n", c); + return false; + } + def = symtab_search(&db->p_types, d); + if (def == NULL) { + pr_warn("default type %s does not exist\n", d); + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) - struct filename_trans_key key; - key.ttype = tgt->value; - key.tclass = cls->value; - key.name = (char *)o; + struct filename_trans_key key; + key.ttype = tgt->value; + key.tclass = cls->value; + key.name = (char *)o; - struct filename_trans_datum *last = NULL; + struct filename_trans_datum *last = NULL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - struct filename_trans_datum *trans = - policydb_filenametr_search(db, &key); + struct filename_trans_datum *trans = + policydb_filenametr_search(db, &key); #else - struct filename_trans_datum *trans = - hashtab_search(&db->filename_trans, &key); + struct filename_trans_datum *trans = + hashtab_search(&db->filename_trans, &key); #endif - while (trans) { - if (ebitmap_get_bit(&trans->stypes, src->value - 1)) { - // Duplicate, overwrite existing data and return - trans->otype = def->value; - return true; - } - if (trans->otype == def->value) - break; - last = trans; - trans = trans->next; - } + while (trans) { + if (ebitmap_get_bit(&trans->stypes, src->value - 1)) { + // Duplicate, overwrite existing data and return + trans->otype = def->value; + return true; + } + if (trans->otype == def->value) + break; + last = trans; + trans = trans->next; + } - if (trans == NULL) { - trans = (struct filename_trans_datum *)kcalloc(1 ,sizeof(*trans), - GFP_ATOMIC); - struct filename_trans_key *new_key = - (struct filename_trans_key *)kmalloc(sizeof(*new_key), - 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); - } + if (trans == NULL) { + trans = (struct filename_trans_datum *)kcalloc(1 ,sizeof(*trans), + GFP_ATOMIC); + struct filename_trans_key *new_key = + (struct filename_trans_key *)kmalloc(sizeof(*new_key), + 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); + } - db->compat_filename_trans_count++; - return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0; + db->compat_filename_trans_count++; + return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0; #else // < 5.7.0, has no filename_trans_key, but struct filename_trans - struct filename_trans key; - key.ttype = tgt->value; - key.tclass = cls->value; - key.name = (char *)o; + struct filename_trans key; + key.ttype = tgt->value; + key.tclass = cls->value; + key.name = (char *)o; - struct filename_trans_datum *trans = - hashtab_search(db->filename_trans, &key); + struct filename_trans_datum *trans = + hashtab_search(db->filename_trans, &key); - if (trans == NULL) { - trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), - 1, GFP_ATOMIC); - if (!trans) { - pr_err("add_filename_trans: Failed to alloc datum\n"); - return false; - } - struct filename_trans *new_key = - (struct filename_trans *)kmalloc(sizeof(*new_key), - GFP_ATOMIC); - if (!new_key) { - pr_err("add_filename_trans: Failed to alloc new_key\n"); - return false; - } - *new_key = key; - new_key->name = kstrdup(key.name, GFP_ATOMIC); - trans->otype = def->value; - hashtab_insert(db->filename_trans, new_key, trans); - } + if (trans == NULL) { + trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), + 1, GFP_ATOMIC); + if (!trans) { + pr_err("add_filename_trans: Failed to alloc datum\n"); + return false; + } + struct filename_trans *new_key = + (struct filename_trans *)kmalloc(sizeof(*new_key), + GFP_ATOMIC); + if (!new_key) { + pr_err("add_filename_trans: Failed to alloc new_key\n"); + return false; + } + *new_key = key; + new_key->name = kstrdup(key.name, GFP_ATOMIC); + trans->otype = def->value; + hashtab_insert(db->filename_trans, new_key, trans); + } - return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) == - 0; + return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) == + 0; #endif } static bool add_genfscon(struct policydb *db, const char *fs_name, - const char *path, const char *context) + const char *path, const char *context) { - return false; + return false; } static void *ksu_realloc(void *old, size_t new_size, size_t old_size) { - // we can't use krealloc, because it may be read-only - void *new = kzalloc(new_size, GFP_ATOMIC); - if (!new) { - return NULL; - } - if (old_size) { - memcpy(new, old, old_size); - } - // we can't use kfree, because it may be read-only - // there maybe some leaks, maybe we can check ptr_write, but it's not a big deal - // kfree(old); - return new; + // we can't use krealloc, because it may be read-only + void *new = kzalloc(new_size, GFP_ATOMIC); + if (!new) { + return NULL; + } + if (old_size) { + memcpy(new, old, old_size); + } + // we can't use kfree, because it may be read-only + // there maybe some leaks, maybe we can check ptr_write, but it's not a big deal + // kfree(old); + return new; } static bool add_type(struct policydb *db, const char *type_name, bool attr) { #ifdef KSU_SUPPORT_ADD_TYPE - struct type_datum *type = symtab_search(&db->p_types, type_name); - if (type) { - pr_warn("Type %s already exists\n", type_name); - return true; - } + struct type_datum *type = symtab_search(&db->p_types, type_name); + if (type) { + pr_warn("Type %s already exists\n", type_name); + return true; + } - u32 value = ++db->p_types.nprim; - type = (struct type_datum *)kzalloc(sizeof(struct type_datum), - GFP_ATOMIC); - if (!type) { - pr_err("add_type: alloc type_datum failed.\n"); - return false; - } + u32 value = ++db->p_types.nprim; + type = (struct type_datum *)kzalloc(sizeof(struct type_datum), + GFP_ATOMIC); + if (!type) { + pr_err("add_type: alloc type_datum failed.\n"); + return false; + } - type->primary = 1; - type->value = value; - type->attribute = attr; + type->primary = 1; + type->value = value; + type->attribute = attr; - char *key = kstrdup(type_name, GFP_ATOMIC); - if (!key) { - pr_err("add_type: alloc key failed.\n"); - return false; - } + char *key = kstrdup(type_name, GFP_ATOMIC); + if (!key) { + pr_err("add_type: alloc key failed.\n"); + return false; + } - if (symtab_insert(&db->p_types, key, type)) { - pr_err("add_type: insert symtab failed.\n"); - return false; - } + if (symtab_insert(&db->p_types, key, type)) { + pr_err("add_type: insert symtab failed.\n"); + return false; + } #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)); + struct ebitmap *new_type_attr_map_array = + ksu_realloc(db->type_attr_map_array, + 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"); - return false; - } + if (!new_type_attr_map_array) { + pr_err("add_type: alloc type_attr_map_array failed\n"); + return false; + } - 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)); + 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)); - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } + if (!new_type_val_to_struct) { + pr_err("add_type: alloc type_val_to_struct failed\n"); + return false; + } - char **new_val_to_name_types = - ksu_realloc(db->sym_val_to_name[SYM_TYPES], - 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; - } + char **new_val_to_name_types = + ksu_realloc(db->sym_val_to_name[SYM_TYPES], + 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; + } - db->type_attr_map_array = new_type_attr_map_array; - ebitmap_init(&db->type_attr_map_array[value - 1]); - ebitmap_set_bit(&db->type_attr_map_array[value - 1], value - 1, 1); + db->type_attr_map_array = new_type_attr_map_array; + ebitmap_init(&db->type_attr_map_array[value - 1]); + ebitmap_set_bit(&db->type_attr_map_array[value - 1], value - 1, 1); - db->type_val_to_struct = new_type_val_to_struct; - db->type_val_to_struct[value - 1] = type; + db->type_val_to_struct = new_type_val_to_struct; + db->type_val_to_struct[value - 1] = type; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - db->sym_val_to_name[SYM_TYPES][value - 1] = key; + db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; + db->sym_val_to_name[SYM_TYPES][value - 1] = key; - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } + int i; + for (i = 0; i < db->p_roles.nprim; ++i) { + ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, + 1); + } - return true; + return true; #elif defined(CONFIG_IS_HW_HISI) - /* + /* * Huawei use type_attr_map and type_val_to_struct. * And use ebitmap not flex_array. */ - size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim; - struct ebitmap *new_type_attr_map = - (krealloc(db->type_attr_map, new_size, GFP_ATOMIC)); + size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim; + struct ebitmap *new_type_attr_map = + (krealloc(db->type_attr_map, new_size, GFP_ATOMIC)); - struct type_datum **new_type_val_to_struct = - krealloc(db->type_val_to_struct, - sizeof(*db->type_val_to_struct) * db->p_types.nprim, - GFP_ATOMIC); + struct type_datum **new_type_val_to_struct = + krealloc(db->type_val_to_struct, + sizeof(*db->type_val_to_struct) * db->p_types.nprim, + GFP_ATOMIC); - if (!new_type_attr_map) { - pr_err("add_type: alloc type_attr_map failed\n"); - return false; - } + if (!new_type_attr_map) { + pr_err("add_type: alloc type_attr_map failed\n"); + return false; + } - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } + if (!new_type_val_to_struct) { + pr_err("add_type: alloc type_val_to_struct failed\n"); + return false; + } - char **new_val_to_name_types = - krealloc(db->sym_val_to_name[SYM_TYPES], - sizeof(char *) * db->symtab[SYM_TYPES].nprim, - GFP_KERNEL); - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } + char **new_val_to_name_types = + krealloc(db->sym_val_to_name[SYM_TYPES], + sizeof(char *) * db->symtab[SYM_TYPES].nprim, + GFP_KERNEL); + if (!new_val_to_name_types) { + pr_err("add_type: alloc val_to_name failed\n"); + return false; + } - db->type_attr_map = new_type_attr_map; - ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO); - ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1); + db->type_attr_map = new_type_attr_map; + ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO); + ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1); - db->type_val_to_struct = new_type_val_to_struct; - db->type_val_to_struct[value - 1] = type; + db->type_val_to_struct = new_type_val_to_struct; + db->type_val_to_struct[value - 1] = type; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - db->sym_val_to_name[SYM_TYPES][value - 1] = key; + db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; + db->sym_val_to_name[SYM_TYPES][value - 1] = key; - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } + int i; + for (i = 0; i < db->p_roles.nprim; ++i) { + ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, + 1); + } - return true; + return true; #else - // flex_array is not extensible, we need to create a new bigger one instead - struct flex_array *new_type_attr_map_array = - flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO); + // flex_array is not extensible, we need to create a new bigger one instead + struct flex_array *new_type_attr_map_array = + flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO); - struct flex_array *new_type_val_to_struct = - flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO); + struct flex_array *new_type_val_to_struct = + flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO); - struct flex_array *new_val_to_name_types = - flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim, - GFP_ATOMIC | __GFP_ZERO); + struct flex_array *new_val_to_name_types = + flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim, + GFP_ATOMIC | __GFP_ZERO); - if (!new_type_attr_map_array) { - pr_err("add_type: alloc type_attr_map_array failed\n"); - return false; - } + if (!new_type_attr_map_array) { + pr_err("add_type: alloc type_attr_map_array failed\n"); + return false; + } - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } + if (!new_type_val_to_struct) { + pr_err("add_type: alloc type_val_to_struct failed\n"); + return false; + } - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } + if (!new_val_to_name_types) { + pr_err("add_type: alloc val_to_name failed\n"); + return false; + } - // preallocate so we don't have to worry about the put ever failing - if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc type_attr_map_array failed\n"); - return false; - } + // preallocate so we don't have to worry about the put ever failing + if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO)) { + pr_err("add_type: prealloc type_attr_map_array failed\n"); + return false; + } - if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc type_val_to_struct_array failed\n"); - return false; - } + if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim, + GFP_ATOMIC | __GFP_ZERO)) { + pr_err("add_type: prealloc type_val_to_struct_array failed\n"); + return false; + } - if (flex_array_prealloc(new_val_to_name_types, 0, - db->symtab[SYM_TYPES].nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc val_to_name_types failed\n"); - return false; - } + if (flex_array_prealloc(new_val_to_name_types, 0, + db->symtab[SYM_TYPES].nprim, + GFP_ATOMIC | __GFP_ZERO)) { + pr_err("add_type: prealloc val_to_name_types failed\n"); + return false; + } - int j; - void *old_elem; - // copy the old data or pointers to new flex arrays - for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) { - 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); - } + int j; + void *old_elem; + // copy the old data or pointers to new flex arrays + for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) { + 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); + } - for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) { - old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j); - if (old_elem) - flex_array_put_ptr(new_type_val_to_struct, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } + for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) { + old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j); + if (old_elem) + flex_array_put_ptr(new_type_val_to_struct, j, old_elem, + GFP_ATOMIC | __GFP_ZERO); + } - for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) { - old_elem = - flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j); - if (old_elem) - flex_array_put_ptr(new_val_to_name_types, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } + for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) { + old_elem = + flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j); + if (old_elem) + flex_array_put_ptr(new_val_to_name_types, j, old_elem, + GFP_ATOMIC | __GFP_ZERO); + } - // store the pointer of old flex arrays first, when assigning new ones we - // should free it - struct flex_array *old_fa; + // store the pointer of old flex arrays first, when assigning new ones we + // should free it + struct flex_array *old_fa; - old_fa = db->type_attr_map_array; - db->type_attr_map_array = new_type_attr_map_array; - if (old_fa) { - flex_array_free(old_fa); - } + old_fa = db->type_attr_map_array; + db->type_attr_map_array = new_type_attr_map_array; + if (old_fa) { + flex_array_free(old_fa); + } - ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1)); - ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1), - value - 1, 1); + ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1)); + ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1), + value - 1, 1); - old_fa = db->type_val_to_struct_array; - db->type_val_to_struct_array = new_type_val_to_struct; - if (old_fa) { - flex_array_free(old_fa); - } - flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type, - GFP_ATOMIC | __GFP_ZERO); + old_fa = db->type_val_to_struct_array; + db->type_val_to_struct_array = new_type_val_to_struct; + if (old_fa) { + flex_array_free(old_fa); + } + flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type, + GFP_ATOMIC | __GFP_ZERO); - old_fa = db->sym_val_to_name[SYM_TYPES]; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - if (old_fa) { - flex_array_free(old_fa); - } - flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key, - GFP_ATOMIC | __GFP_ZERO); + old_fa = db->sym_val_to_name[SYM_TYPES]; + db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; + if (old_fa) { + flex_array_free(old_fa); + } + flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key, + GFP_ATOMIC | __GFP_ZERO); - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } - return true; + int i; + for (i = 0; i < db->p_roles.nprim; ++i) { + ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, + 1); + } + return true; #endif #else - return false; + return false; #endif } static bool set_type_state(struct policydb *db, const char *type_name, - bool permissive) + bool permissive) { - struct type_datum *type; - if (type_name == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - type = (struct type_datum *)(node->datum); - if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) - pr_info("Could not set bit in permissive map\n"); - }; - } else { - type = (struct type_datum *)symtab_search(&db->p_types, - type_name); - if (type == NULL) { - pr_info("type %s does not exist\n", type_name); - return false; - } - if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) { - pr_info("Could not set bit in permissive map\n"); - return false; - } - } - return true; + struct type_datum *type; + if (type_name == NULL) { + struct hashtab_node *node; + ksu_hashtab_for_each(db->p_types.table, node) + { + type = (struct type_datum *)(node->datum); + if (ebitmap_set_bit(&db->permissive_map, type->value, + permissive)) + pr_info("Could not set bit in permissive map\n"); + }; + } else { + type = (struct type_datum *)symtab_search(&db->p_types, + type_name); + if (type == NULL) { + pr_info("type %s does not exist\n", type_name); + return false; + } + if (ebitmap_set_bit(&db->permissive_map, type->value, + permissive)) { + pr_info("Could not set bit in permissive map\n"); + return false; + } + } + return true; } static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, - struct type_datum *attr) + struct type_datum *attr) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) - struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1]; + struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1]; #elif defined(CONFIG_IS_HW_HISI) - /* + /* * HISI_SELINUX_EBITMAP_RO is Huawei's unique features. */ - struct ebitmap *sattr = &db->type_attr_map[type->value - 1], - HISI_SELINUX_EBITMAP_RO; + struct ebitmap *sattr = &db->type_attr_map[type->value - 1], + HISI_SELINUX_EBITMAP_RO; #else - struct ebitmap *sattr = - flex_array_get(db->type_attr_map_array, type->value - 1); + struct ebitmap *sattr = + flex_array_get(db->type_attr_map_array, type->value - 1); #endif - ebitmap_set_bit(sattr, attr->value - 1, 1); + ebitmap_set_bit(sattr, attr->value - 1, 1); - struct hashtab_node *node; - struct constraint_node *n; - struct constraint_expr *e; - ksu_hashtab_for_each(db->p_classes.table, node) - { - struct class_datum *cls = (struct class_datum *)(node->datum); - 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_set_bit(&e->names, - type->value - 1, 1); - } - } - } - }; + struct hashtab_node *node; + struct constraint_node *n; + struct constraint_expr *e; + ksu_hashtab_for_each(db->p_classes.table, node) + { + struct class_datum *cls = (struct class_datum *)(node->datum); + 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_set_bit(&e->names, + type->value - 1, 1); + } + } + } + }; } 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) { - pr_info("type %s does not exist\n", type); - return false; - } else if (type_d->attribute) { - pr_info("type %s is an attribute\n", attr); - return false; - } + struct type_datum *type_d = symtab_search(&db->p_types, type); + if (type_d == NULL) { + pr_info("type %s does not exist\n", type); + return false; + } else if (type_d->attribute) { + pr_info("type %s is an attribute\n", attr); + return false; + } - struct type_datum *attr_d = symtab_search(&db->p_types, attr); - if (attr_d == NULL) { - pr_info("attribute %s does not exist\n", type); - return false; - } else if (!attr_d->attribute) { - pr_info("type %s is not an attribute \n", attr); - return false; - } + struct type_datum *attr_d = symtab_search(&db->p_types, attr); + if (attr_d == NULL) { + pr_info("attribute %s does not exist\n", type); + return false; + } else if (!attr_d->attribute) { + pr_info("type %s is not an attribute \n", attr); + return false; + } - add_typeattribute_raw(db, type_d, attr_d); - return true; + add_typeattribute_raw(db, type_d, attr_d); + return true; } ////////////////////////////////////////////////////////////////////////// @@ -965,106 +965,106 @@ static bool add_typeattribute(struct policydb *db, const char *type, // Operation on types bool ksu_type(struct policydb *db, const char *name, const char *attr) { - return add_type(db, name, false) && add_typeattribute(db, name, attr); + return add_type(db, name, false) && add_typeattribute(db, name, attr); } bool ksu_attribute(struct policydb *db, const char *name) { - return add_type(db, name, true); + return add_type(db, name, true); } bool ksu_permissive(struct policydb *db, const char *type) { - return set_type_state(db, type, true); + return set_type_state(db, type, true); } bool ksu_enforce(struct policydb *db, const char *type) { - return set_type_state(db, type, false); + return set_type_state(db, type, false); } bool ksu_typeattribute(struct policydb *db, const char *type, const char *attr) { - return add_typeattribute(db, type, attr); + return add_typeattribute(db, type, attr); } bool ksu_exists(struct policydb *db, const char *type) { - return symtab_search(&db->p_types, type) != NULL; + return symtab_search(&db->p_types, type) != NULL; } // 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); + 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); + 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); + return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITALLOW, false); } bool ksu_dontaudit(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_AUDITDENY, true); + return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITDENY, true); } // 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); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, + false); } bool ksu_auditallowxperm(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_AUDITALLOW, - false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, + false); } bool ksu_dontauditxperm(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_DONTAUDIT, - false); + return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, + false); } // 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) { - if (obj) { - return add_filename_trans(db, src, tgt, cls, def, obj); - } else { - return add_type_rule(db, src, tgt, cls, def, AVTAB_TRANSITION); - } + if (obj) { + return add_filename_trans(db, src, tgt, cls, def, obj); + } else { + return add_type_rule(db, src, tgt, cls, def, AVTAB_TRANSITION); + } } 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); + 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); + return add_type_rule(db, src, tgt, cls, def, AVTAB_MEMBER); } // File system labeling bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path, - const char *ctx) + const char *ctx) { - return add_genfscon(db, fs_name, path, ctx); + return add_genfscon(db, fs_name, path, ctx); } diff --git a/kernel/selinux/sepolicy.h b/kernel/selinux/sepolicy.h index 675d1499..fd062ce6 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/sucompat.c b/kernel/sucompat.c index 048d50ef..acc64e77 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -39,77 +39,77 @@ bool ksu_sucompat_hook_state __read_mostly = true; static inline 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 + /* 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; + 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 inline char __user *sh_user_path(void) { - return userspace_stack_buffer(sh_path, sizeof(sh_path)); + return userspace_stack_buffer(sh_path, sizeof(sh_path)); } static inline char __user *ksud_user_path(void) { - return userspace_stack_buffer(ksud_path, sizeof(ksud_path)); + return userspace_stack_buffer(ksud_path, sizeof(ksud_path)); } int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *__unused_flags) + int *__unused_flags) { #ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_hook_state) { - return 0; - } + if (!ksu_sucompat_hook_state) { + return 0; + } #endif #ifndef CONFIG_KSU_SUSFS_SUS_SU - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid(current_uid().val)) { + return 0; + } #endif #ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su) + 1] = {0}; + char path[sizeof(su) + 1] = {0}; #else - char path[sizeof(su) + 1]; - memset(path, 0, sizeof(path)); + char path[sizeof(su) + 1]; + memset(path, 0, sizeof(path)); #endif - 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, "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) && defined(CONFIG_KSU_SUSFS_SUS_SU) struct filename* susfs_ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) { - struct filename *name = getname_flags(*filename_user, getname_statx_lookup_flags(*flags), NULL); + struct filename *name = getname_flags(*filename_user, getname_statx_lookup_flags(*flags), NULL); - if (unlikely(IS_ERR(name) || name->name == NULL)) { - return name; - } + if (unlikely(IS_ERR(name) || name->name == NULL)) { + return name; + } - if (likely(memcmp(name->name, su, sizeof(su)))) { - return name; - } + if (likely(memcmp(name->name, su, sizeof(su)))) { + return name; + } - const char sh[] = SH_PATH; + const char sh[] = SH_PATH; #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "vfs_fstatat", sh); + ksu_sulog_report_syscall(current_uid().val, NULL, "vfs_fstatat", sh); #endif - pr_info("vfs_fstatat su->sh!\n"); - memcpy((void *)name->name, sh, sizeof(sh)); - return name; + pr_info("vfs_fstatat su->sh!\n"); + memcpy((void *)name->name, sh, sizeof(sh)); + return name; } #endif @@ -117,282 +117,282 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) { #ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_hook_state) { - return 0; - } + if (!ksu_sucompat_hook_state) { + return 0; + } #endif #ifndef CONFIG_KSU_SUSFS_SUS_SU - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid(current_uid().val)) { + return 0; + } #endif - if (unlikely(!filename_user)) { - return 0; - } + if (unlikely(!filename_user)) { + return 0; + } #ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su) + 1] = {0}; + char path[sizeof(su) + 1] = {0}; #else - char path[sizeof(su) + 1]; - memset(path, 0, sizeof(path)); + char path[sizeof(su) + 1]; + memset(path, 0, sizeof(path)); #endif // 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; } // 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; #ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_hook_state) { - return 0; - } + if (!ksu_sucompat_hook_state) { + return 0; + } #endif - 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, sizeof(su)))) - return 0; - + if (likely(memcmp(filename->name, su, sizeof(su)))) + return 0; + #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "execve", filename->name); + ksu_sulog_report_syscall(current_uid().val, NULL, "execve", filename->name); #ifndef CONFIG_KSU_SUSFS_SUS_SU - bool is_allowed = ksu_is_allow_uid(current_uid().val); + bool is_allowed = ksu_is_allow_uid(current_uid().val); #endif #endif #ifndef CONFIG_KSU_SUSFS_SUS_SU #if __SULOG_GATE - if (!is_allowed) - return 0; - - ksu_sulog_report_su_attempt(current_uid().val, NULL, filename->name, is_allowed); + if (!is_allowed) + return 0; + + ksu_sulog_report_su_attempt(current_uid().val, NULL, filename->name, is_allowed); #else - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid(current_uid().val)) { + return 0; + } #endif #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_to_root(); + escape_to_root(); - return 0; + return 0; } int ksu_handle_execve_sucompat(int *fd, 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; + //const char su[] = SU_PATH; #ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su) + 1] = {0}; + char path[sizeof(su) + 1] = {0}; #else - char path[sizeof(su) + 1]; + char path[sizeof(su) + 1]; #endif #ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_hook_state) { - return 0; - } + if (!ksu_sucompat_hook_state) { + return 0; + } #endif - if (unlikely(!filename_user)) - return 0; + if (unlikely(!filename_user)) + return 0; - /* - * nofault variant fails silently due to pagefault_disable - * some cpus dont really have that good speculative execution - * access_ok to substitute set_fs, we check if pointer is accessible - */ - if (!ksu_access_ok(*filename_user, sizeof(path))) - return 0; + /* + * nofault variant fails silently due to pagefault_disable + * some cpus dont really have that good speculative execution + * access_ok to substitute set_fs, we check if pointer is accessible + */ + if (!ksu_access_ok(*filename_user, sizeof(path))) + return 0; - // success = returns number of bytes and should be less than path - long len = strncpy_from_user(path, *filename_user, sizeof(path)); - if (len <= 0 || len > sizeof(path)) - return 0; - // strncpy_from_user_nofault does this too - path[sizeof(path) - 1] = '\0'; + // success = returns number of bytes and should be less than path + long len = strncpy_from_user(path, *filename_user, sizeof(path)); + if (len <= 0 || len > sizeof(path)) + return 0; + // strncpy_from_user_nofault does this too + path[sizeof(path) - 1] = '\0'; - if (likely(memcmp(path, su, sizeof(su)))) - return 0; + if (likely(memcmp(path, su, sizeof(su)))) + return 0; #if __SULOG_GATE - ksu_sulog_report_syscall(current_uid().val, NULL, "execve", path); - bool is_allowed = ksu_is_allow_uid(current_uid().val); - if (!is_allowed) - return 0; - - ksu_sulog_report_su_attempt(current_uid().val, NULL, path, is_allowed); + ksu_sulog_report_syscall(current_uid().val, NULL, "execve", path); + bool is_allowed = ksu_is_allow_uid(current_uid().val); + if (!is_allowed) + return 0; + + ksu_sulog_report_su_attempt(current_uid().val, NULL, path, is_allowed); #else - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid(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_to_root(); + escape_to_root(); - return 0; + return 0; } // dummified int ksu_handle_devpts(struct inode *inode) { - return 0; + return 0; } int __ksu_handle_devpts(struct inode *inode) { #ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_hook_state) - return 0; + if (!ksu_sucompat_hook_state) + return 0; #endif - 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(uid))) - return 0; + if (likely(!ksu_is_allow_uid(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_devpts_sid && sec) - sec->sid = ksu_devpts_sid; + if (ksu_devpts_sid && sec) + sec->sid = ksu_devpts_sid; - return 0; + return 0; } #ifdef CONFIG_KSU_KPROBES_HOOK static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *mode = (int *)&PT_REGS_PARM3(real_regs); + struct pt_regs *real_regs = PT_REAL_REGS(regs); + int *dfd = (int *)&PT_REGS_PARM1(real_regs); + const char __user **filename_user = + (const char **)&PT_REGS_PARM2(real_regs); + int *mode = (int *)&PT_REGS_PARM3(real_regs); - return ksu_handle_faccessat(dfd, filename_user, mode, NULL); + return ksu_handle_faccessat(dfd, filename_user, mode, NULL); } static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs); + struct pt_regs *real_regs = PT_REAL_REGS(regs); + int *dfd = (int *)&PT_REGS_PARM1(real_regs); + const char __user **filename_user = + (const char **)&PT_REGS_PARM2(real_regs); + int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs); - return ksu_handle_stat(dfd, filename_user, flags); + return ksu_handle_stat(dfd, filename_user, flags); } static int 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); + struct pt_regs *real_regs = PT_REAL_REGS(regs); + const char __user **filename_user = + (const char **)&PT_REGS_PARM1(real_regs); - return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, - NULL); + return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, + NULL); } static struct kprobe *su_kps[6]; static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) { - struct inode *inode; + struct inode *inode; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) - struct file *file = (struct file *)PT_REGS_PARM2(regs); - inode = file->f_path.dentry->d_inode; + struct file *file = (struct file *)PT_REGS_PARM2(regs); + inode = file->f_path.dentry->d_inode; #else - inode = (struct inode *)PT_REGS_PARM2(regs); + inode = (struct inode *)PT_REGS_PARM2(regs); #endif - return ksu_handle_devpts(inode); + return ksu_handle_devpts(inode); } static struct kprobe *init_kprobe(const char *name, - kprobe_pre_handler_t handler) + kprobe_pre_handler_t handler) { - struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL); - if (!kp) - return NULL; - kp->symbol_name = name; - kp->pre_handler = handler; + struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL); + if (!kp) + return NULL; + kp->symbol_name = name; + kp->pre_handler = handler; - int ret = register_kprobe(kp); - pr_info("sucompat: register_%s kprobe: %d\n", name, ret); - if (ret) { - kfree(kp); - return NULL; - } + int ret = register_kprobe(kp); + pr_info("sucompat: register_%s kprobe: %d\n", name, ret); + if (ret) { + kfree(kp); + return NULL; + } - return kp; + return kp; } static void destroy_kprobe(struct kprobe **kp_ptr) { - struct kprobe *kp = *kp_ptr; - if (!kp) - return; - unregister_kprobe(kp); - synchronize_rcu(); - kfree(kp); - *kp_ptr = NULL; + struct kprobe *kp = *kp_ptr; + if (!kp) + return; + unregister_kprobe(kp); + synchronize_rcu(); + kfree(kp); + *kp_ptr = NULL; } #endif @@ -400,28 +400,28 @@ static void destroy_kprobe(struct kprobe **kp_ptr) void ksu_sucompat_init(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); - su_kps[1] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre); - su_kps[2] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); - su_kps[3] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre); - su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre); - su_kps[5] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); + su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); + su_kps[1] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre); + su_kps[2] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); + su_kps[3] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre); + su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre); + su_kps[5] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); #else - ksu_sucompat_hook_state = true; - pr_info("ksu_sucompat init\n"); + ksu_sucompat_hook_state = true; + pr_info("ksu_sucompat init\n"); #endif } void ksu_sucompat_exit(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - int i; - for (i = 0; i < ARRAY_SIZE(su_kps); i++) { - destroy_kprobe(&su_kps[i]); - } + int i; + for (i = 0; i < ARRAY_SIZE(su_kps); i++) { + destroy_kprobe(&su_kps[i]); + } #else - ksu_sucompat_hook_state = false; - pr_info("ksu_sucompat exit\n"); + ksu_sucompat_hook_state = false; + pr_info("ksu_sucompat exit\n"); #endif } @@ -433,34 +433,34 @@ int susfs_sus_su_working_mode = 0; static bool ksu_is_su_kps_enabled(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - int i; - for (i = 0; i < ARRAY_SIZE(su_kps); i++) { - if (su_kps[i]) { - return true; - } - } + int i; + for (i = 0; i < ARRAY_SIZE(su_kps); i++) { + if (su_kps[i]) { + return true; + } + } #endif - return false; + return false; } void ksu_susfs_disable_sus_su(void) { - susfs_is_sus_su_hooks_enabled = false; - ksu_devpts_hook = false; - susfs_sus_su_working_mode = SUS_SU_DISABLED; - // Re-enable the su_kps for user, users need to toggle off the kprobe hooks again in ksu manager if they want it disabled. - if (!ksu_is_su_kps_enabled()) { - ksu_sucompat_init(); - ksu_su_compat_enabled = true; - } + susfs_is_sus_su_hooks_enabled = false; + ksu_devpts_hook = false; + susfs_sus_su_working_mode = SUS_SU_DISABLED; + // Re-enable the su_kps for user, users need to toggle off the kprobe hooks again in ksu manager if they want it disabled. + if (!ksu_is_su_kps_enabled()) { + ksu_sucompat_init(); + ksu_su_compat_enabled = true; + } } void ksu_susfs_enable_sus_su(void) { - if (ksu_is_su_kps_enabled()) { - ksu_sucompat_exit(); - ksu_su_compat_enabled = false; - } - susfs_is_sus_su_hooks_enabled = true; - ksu_devpts_hook = true; - susfs_sus_su_working_mode = SUS_SU_WITH_HOOKS; + if (ksu_is_su_kps_enabled()) { + ksu_sucompat_exit(); + ksu_su_compat_enabled = false; + } + susfs_is_sus_su_hooks_enabled = true; + ksu_devpts_hook = true; + susfs_sus_su_working_mode = SUS_SU_WITH_HOOKS; } #endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU \ No newline at end of file diff --git a/kernel/sulog.c b/kernel/sulog.c index 5d29862e..4184e106 100644 --- a/kernel/sulog.c +++ b/kernel/sulog.c @@ -30,380 +30,380 @@ static bool sulog_enabled = true; 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); + ktime_get_real_ts64(&ts); - time64_to_tm(ts.tv_sec - sys_tz.tz_minuteswest * 60, 0, &tm); + 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) { - char *kbuf; + char *kbuf; - if (!full_comm || buf_len <= 0) - return; + if (!full_comm || buf_len <= 0) + return; - if (comm && strlen(comm) > 0) { + if (comm && strlen(comm) > 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(full_comm, comm, buf_len); + strscpy(full_comm, comm, buf_len); #else - strlcpy(full_comm, comm, buf_len); + strlcpy(full_comm, comm, buf_len); #endif - } else { - kbuf = kmalloc(buf_len, GFP_ATOMIC); - if (!kbuf) { - pr_err("sulog: failed to allocate memory for kbuf\n"); - return; - } + } else { + kbuf = kmalloc(buf_len, GFP_ATOMIC); + if (!kbuf) { + pr_err("sulog: failed to allocate memory for kbuf\n"); + return; + } - int n = get_cmdline(current, kbuf, buf_len); + int n = get_cmdline(current, kbuf, buf_len); - if (n <= 0) { + if (n <= 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(full_comm, current->comm, buf_len); + strscpy(full_comm, current->comm, buf_len); #else - strlcpy(full_comm, current->comm, buf_len); + strlcpy(full_comm, current->comm, buf_len); #endif - } else { - for (int i = 0; i < n; i++) { - if (kbuf[i] == '\0') kbuf[i] = ' '; - } - kbuf[n < buf_len ? n : buf_len - 1] = '\0'; + } else { + for (int i = 0; i < n; i++) { + if (kbuf[i] == '\0') kbuf[i] = ' '; + } + kbuf[n < buf_len ? n : buf_len - 1] = '\0'; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(full_comm, kbuf, buf_len); + strscpy(full_comm, kbuf, buf_len); #else - strlcpy(full_comm, kbuf, buf_len); + strlcpy(full_comm, kbuf, buf_len); #endif - } + } - kfree(kbuf); - } + kfree(kbuf); + } } static bool dedup_should_print(uid_t uid, u8 type, - const char *content, size_t len) + 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; - - mutex_lock(&sulog_mutex); - list_splice_init(&sulog_queue, &local_queue); - mutex_unlock(&sulog_mutex); - - 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; - } - - if (fp->f_inode->i_size > SULOG_MAX_SIZE) { - pr_info("sulog: log file exceeds maximum size, clearing...\n"); - 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); - } - - vfs_fsync(fp, 0); - filp_close(fp, 0); - + struct file *fp; + struct sulog_entry *entry, *tmp; + LIST_HEAD(local_queue); + loff_t pos = 0; + + mutex_lock(&sulog_mutex); + list_splice_init(&sulog_queue, &local_queue); + mutex_unlock(&sulog_mutex); + + 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; + } + + if (fp->f_inode->i_size > SULOG_MAX_SIZE) { + pr_info("sulog: log file exceeds maximum size, clearing...\n"); + 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); + } + + 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(const char *content) { - struct sulog_entry *entry; - - if (!sulog_enabled || !content) - return; - - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - pr_err("sulog: failed to allocate memory for log entry\n"); - return; - } - + struct sulog_entry *entry; + + if (!sulog_enabled || !content) + return; + + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + pr_err("sulog: failed to allocate memory for log entry\n"); + return; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - strscpy(entry->content, content, SULOG_ENTRY_MAX_LEN - 1); + strscpy(entry->content, content, SULOG_ENTRY_MAX_LEN - 1); #else - strlcpy(entry->content, content, SULOG_ENTRY_MAX_LEN - 1); + strlcpy(entry->content, content, SULOG_ENTRY_MAX_LEN - 1); #endif - - mutex_lock(&sulog_mutex); - list_add_tail(&entry->list, &sulog_queue); - mutex_unlock(&sulog_mutex); - - if (sulog_workqueue) - queue_work(sulog_workqueue, &sulog_work); + + mutex_lock(&sulog_mutex); + list_add_tail(&entry->list, &sulog_queue); + mutex_unlock(&sulog_mutex); + + 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 *timestamp, *full_comm, *log_buf; - - if (!sulog_enabled) - return; - - timestamp = kmalloc(32, GFP_ATOMIC); - full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); - log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); - - if (!timestamp || !full_comm || !log_buf) { - pr_err("sulog: failed to allocate memory for su_grant log\n"); - goto cleanup; - } - - get_timestamp(timestamp, 32); - - ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); - - snprintf(log_buf, SULOG_ENTRY_MAX_LEN, - "[%s] SU_GRANT: UID=%d COMM=%s METHOD=%s PID=%d\n", - timestamp, uid, full_comm, - method ? method : "unknown", current->pid); + char *timestamp, *full_comm, *log_buf; + + if (!sulog_enabled) + return; + + timestamp = kmalloc(32, GFP_ATOMIC); + full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); + log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); + + if (!timestamp || !full_comm || !log_buf) { + pr_err("sulog: failed to allocate memory for su_grant log\n"); + goto cleanup; + } + + get_timestamp(timestamp, 32); + + ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); + + snprintf(log_buf, SULOG_ENTRY_MAX_LEN, + "[%s] SU_GRANT: UID=%d COMM=%s METHOD=%s PID=%d\n", + timestamp, uid, full_comm, + method ? method : "unknown", current->pid); - if (!dedup_should_print(uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf))) - goto cleanup; - - sulog_add_entry(log_buf); - + if (!dedup_should_print(uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf))) + goto cleanup; + + sulog_add_entry(log_buf); + cleanup: - if (timestamp) kfree(timestamp); - if (full_comm) kfree(full_comm); - if (log_buf) kfree(log_buf); + if (timestamp) kfree(timestamp); + if (full_comm) kfree(full_comm); + if (log_buf) kfree(log_buf); } void ksu_sulog_report_su_attempt(uid_t uid, const char *comm, const char *target_path, bool success) { - char *timestamp, *full_comm, *log_buf; - - if (!sulog_enabled) - return; - - timestamp = kmalloc(32, GFP_ATOMIC); - full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); - log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); - - if (!timestamp || !full_comm || !log_buf) { - pr_err("sulog: failed to allocate memory for su_attempt log\n"); - goto cleanup; - } - - get_timestamp(timestamp, 32); - - ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); - - snprintf(log_buf, SULOG_ENTRY_MAX_LEN, - "[%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); + char *timestamp, *full_comm, *log_buf; + + if (!sulog_enabled) + return; + + timestamp = kmalloc(32, GFP_ATOMIC); + full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); + log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); + + if (!timestamp || !full_comm || !log_buf) { + pr_err("sulog: failed to allocate memory for su_attempt log\n"); + goto cleanup; + } + + get_timestamp(timestamp, 32); + + ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); + + snprintf(log_buf, SULOG_ENTRY_MAX_LEN, + "[%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); - if (!dedup_should_print(uid, DEDUP_SU_ATTEMPT, log_buf, strlen(log_buf))) - goto cleanup; - - sulog_add_entry(log_buf); - + if (!dedup_should_print(uid, DEDUP_SU_ATTEMPT, log_buf, strlen(log_buf))) + goto cleanup; + + sulog_add_entry(log_buf); + cleanup: - if (timestamp) kfree(timestamp); - if (full_comm) kfree(full_comm); - if (log_buf) kfree(log_buf); + if (timestamp) kfree(timestamp); + if (full_comm) kfree(full_comm); + if (log_buf) kfree(log_buf); } void ksu_sulog_report_permission_check(uid_t uid, const char *comm, bool allowed) { - char *timestamp, *full_comm, *log_buf; - - if (!sulog_enabled) - return; - - timestamp = kmalloc(32, GFP_ATOMIC); - full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); - log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); - - if (!timestamp || !full_comm || !log_buf) { - pr_err("sulog: failed to allocate memory for permission_check log\n"); - goto cleanup; - } - - get_timestamp(timestamp, 32); - - ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); - - snprintf(log_buf, SULOG_ENTRY_MAX_LEN, - "[%s] PERM_CHECK: UID=%d COMM=%s RESULT=%s PID=%d\n", - timestamp, uid, full_comm, - allowed ? "ALLOWED" : "DENIED", current->pid); + char *timestamp, *full_comm, *log_buf; + + if (!sulog_enabled) + return; + + timestamp = kmalloc(32, GFP_ATOMIC); + full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); + log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); + + if (!timestamp || !full_comm || !log_buf) { + pr_err("sulog: failed to allocate memory for permission_check log\n"); + goto cleanup; + } + + get_timestamp(timestamp, 32); + + ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); + + snprintf(log_buf, SULOG_ENTRY_MAX_LEN, + "[%s] PERM_CHECK: UID=%d COMM=%s RESULT=%s PID=%d\n", + timestamp, uid, full_comm, + allowed ? "ALLOWED" : "DENIED", current->pid); - if (!dedup_should_print(uid, DEDUP_PERM_CHECK, log_buf, strlen(log_buf))) - goto cleanup; - - sulog_add_entry(log_buf); - + if (!dedup_should_print(uid, DEDUP_PERM_CHECK, log_buf, strlen(log_buf))) + goto cleanup; + + sulog_add_entry(log_buf); + cleanup: - if (timestamp) kfree(timestamp); - if (full_comm) kfree(full_comm); - if (log_buf) kfree(log_buf); + if (timestamp) kfree(timestamp); + if (full_comm) kfree(full_comm); + if (log_buf) kfree(log_buf); } void ksu_sulog_report_manager_operation(const char *operation, uid_t manager_uid, uid_t target_uid) { - char *timestamp, *full_comm, *log_buf; - - if (!sulog_enabled) - return; - - timestamp = kmalloc(32, GFP_ATOMIC); - full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); - log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); - - if (!timestamp || !full_comm || !log_buf) { - pr_err("sulog: failed to allocate memory for manager_operation log\n"); - goto cleanup; - } - - get_timestamp(timestamp, 32); + char *timestamp, *full_comm, *log_buf; + + if (!sulog_enabled) + return; + + timestamp = kmalloc(32, GFP_ATOMIC); + full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); + log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); + + if (!timestamp || !full_comm || !log_buf) { + pr_err("sulog: failed to allocate memory for manager_operation log\n"); + goto cleanup; + } + + get_timestamp(timestamp, 32); - ksu_get_cmdline(full_comm, NULL, SULOG_COMM_LEN); - - snprintf(log_buf, SULOG_ENTRY_MAX_LEN, - "[%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); + ksu_get_cmdline(full_comm, NULL, SULOG_COMM_LEN); + + snprintf(log_buf, SULOG_ENTRY_MAX_LEN, + "[%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); - if (!dedup_should_print(manager_uid, DEDUP_MANAGER_OP, log_buf, strlen(log_buf))) - goto cleanup; - - sulog_add_entry(log_buf); - + if (!dedup_should_print(manager_uid, DEDUP_MANAGER_OP, log_buf, strlen(log_buf))) + goto cleanup; + + sulog_add_entry(log_buf); + cleanup: - if (timestamp) kfree(timestamp); - if (full_comm) kfree(full_comm); - if (log_buf) kfree(log_buf); + if (timestamp) kfree(timestamp); + if (full_comm) kfree(full_comm); + if (log_buf) kfree(log_buf); } void ksu_sulog_report_syscall(uid_t uid, const char *comm, - const char *syscall, const char *args) + const char *syscall, const char *args) { - char *timestamp, *full_comm, *log_buf; + char *timestamp, *full_comm, *log_buf; - if (!sulog_enabled) - return; + if (!sulog_enabled) + return; - timestamp = kmalloc(32, GFP_ATOMIC); - full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); - log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); + timestamp = kmalloc(32, GFP_ATOMIC); + full_comm = kmalloc(SULOG_COMM_LEN, GFP_ATOMIC); + log_buf = kmalloc(SULOG_ENTRY_MAX_LEN, GFP_ATOMIC); - if (!timestamp || !full_comm || !log_buf) { - pr_err("sulog: failed to allocate memory for syscall log\n"); - goto cleanup; - } + if (!timestamp || !full_comm || !log_buf) { + pr_err("sulog: failed to allocate memory for syscall log\n"); + goto cleanup; + } - get_timestamp(timestamp, 32); - - ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); + get_timestamp(timestamp, 32); + + ksu_get_cmdline(full_comm, comm, SULOG_COMM_LEN); - snprintf(log_buf, SULOG_ENTRY_MAX_LEN, - "[%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, SULOG_ENTRY_MAX_LEN, + "[%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); - if (!dedup_should_print(uid, DEDUP_SYSCALL, log_buf, strlen(log_buf))) - goto cleanup; + if (!dedup_should_print(uid, DEDUP_SYSCALL, log_buf, strlen(log_buf))) + goto cleanup; - sulog_add_entry(log_buf); + sulog_add_entry(log_buf); cleanup: - if (timestamp) kfree(timestamp); - if (full_comm) kfree(full_comm); - if (log_buf) kfree(log_buf); + if (timestamp) kfree(timestamp); + if (full_comm) kfree(full_comm); + if (log_buf) kfree(log_buf); } int ksu_sulog_init(void) { - 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; + 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; } void ksu_sulog_exit(void) { - struct sulog_entry *entry, *tmp; - - sulog_enabled = false; - - if (sulog_workqueue) { - flush_workqueue(sulog_workqueue); - destroy_workqueue(sulog_workqueue); - sulog_workqueue = NULL; - } - - mutex_lock(&sulog_mutex); - list_for_each_entry_safe(entry, tmp, &sulog_queue, list) { - list_del(&entry->list); - kfree(entry); - } - mutex_unlock(&sulog_mutex); - - pr_info("sulog: cleaned up successfully\n"); + struct sulog_entry *entry, *tmp; + + sulog_enabled = false; + + if (sulog_workqueue) { + flush_workqueue(sulog_workqueue); + destroy_workqueue(sulog_workqueue); + sulog_workqueue = NULL; + } + + mutex_lock(&sulog_mutex); + list_for_each_entry_safe(entry, tmp, &sulog_queue, list) { + list_del(&entry->list); + kfree(entry); + } + mutex_unlock(&sulog_mutex); + + pr_info("sulog: cleaned up successfully\n"); } #endif // __SULOG_GATE diff --git a/kernel/sulog.h b/kernel/sulog.h index b6279103..59d2dafa 100644 --- a/kernel/sulog.h +++ b/kernel/sulog.h @@ -58,8 +58,8 @@ static inline u32 dedup_calc_hash(const char *content, size_t 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 new file mode 100644 index 00000000..627a916f --- /dev/null +++ b/kernel/supercalls.c @@ -0,0 +1,609 @@ +#include "supercalls.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "allowlist.h" +#include "klog.h" // IWYU pragma: keep +#include "ksud.h" +#include "manager.h" +#include "sulog.h" +#include "selinux/selinux.h" +#include "kernel_compat.h" +#include "throne_comm.h" +#include "dynamic_manager.h" + +#ifdef CONFIG_KSU_MANUAL_SU +#include "manual_su.h" +#endif + +// Forward declarations from core_hook.c +extern void escape_to_root(void); +extern void nuke_ext4_sysfs(void); +extern bool ksu_module_mounted; +extern int handle_sepolicy(unsigned long arg3, void __user *arg4); +extern void ksu_sucompat_init(void); +extern void ksu_sucompat_exit(void); + +// Forward declaration for anon_ksu_fops +static const struct file_operations anon_ksu_fops; + +static bool ksu_su_compat_enabled = true; +bool ksu_uid_scanner_enabled = false; + +// Permission check functions +bool perm_check_manager(void) +{ + return is_manager(); +} + +bool perm_check_root(void) +{ + return current_uid().val == 0; +} + +bool perm_check_basic(void) +{ + return current_uid().val == 0 || is_manager(); +} + +bool perm_check_all(void) +{ + return true; // No permission check +} + +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); + } + } +} + +static int do_grant_root(void __user *arg) +{ + // Check if current UID is allowed + bool is_allowed = is_manager() || ksu_is_allow_uid(current_uid().val); + + if (!is_allowed) { + return -EPERM; + } + + pr_info("allow root for: %d\n", current_uid().val); + escape_to_root(); + + return 0; +} + +static int do_get_info(void __user *arg) +{ + struct ksu_get_info_cmd cmd = {.version = KERNEL_SU_VERSION, .flags = 0}; + +#ifdef MODULE + cmd.flags |= 0x1; +#endif + if (is_manager()) { + cmd.flags |= 0x2; + } + + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_version: copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int do_report_event(void __user *arg) +{ + struct ksu_report_event_cmd cmd; + + 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"); + 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"); + } + break; + } + case EVENT_MODULE_MOUNTED: { + ksu_module_mounted = true; + pr_info("module mounted!\n"); + nuke_ext4_sysfs(); + break; + } + default: + break; + } + + return 0; +} + +static int do_set_sepolicy(void __user *arg) +{ + struct ksu_set_sepolicy_cmd cmd; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } + + return handle_sepolicy(cmd.cmd, (void __user *)cmd.arg); +} + +static int do_check_safemode(void __user *arg) +{ + struct ksu_check_safemode_cmd cmd; + + cmd.in_safe_mode = ksu_is_safe_mode(); + + 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; + } + + return 0; +} + +static int do_get_allow_list(void __user *arg) +{ + struct ksu_get_allow_list_cmd cmd; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } + + bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, true); + + if (!success) { + return -EFAULT; + } + + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_allow_list: copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int do_get_deny_list(void __user *arg) +{ + struct ksu_get_allow_list_cmd cmd; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } + + bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, false); + + if (!success) { + return -EFAULT; + } + + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("get_deny_list: copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int do_uid_granted_root(void __user *arg) +{ + struct ksu_uid_granted_root_cmd cmd; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } + + cmd.granted = ksu_is_allow_uid(cmd.uid); + + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("uid_granted_root: copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int do_uid_should_umount(void __user *arg) +{ + struct ksu_uid_should_umount_cmd cmd; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + return -EFAULT; + } + + 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; + } + + return 0; +} + +static int do_get_manager_uid(void __user *arg) +{ + struct ksu_get_manager_uid_cmd cmd; + + 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; + } + + return 0; +} + +static int do_get_app_profile(void __user *arg) +{ + 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 (!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; + } + + return 0; +} + +static int do_set_app_profile(void __user *arg) +{ + 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 (!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); +#endif + return -EFAULT; + } + + return 0; +} + +static int do_is_su_enabled(void __user *arg) +{ + struct ksu_is_su_enabled_cmd cmd; + + cmd.enabled = ksu_su_compat_enabled; + + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("is_su_enabled: copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int do_enable_su(void __user *arg) +{ + struct ksu_enable_su_cmd cmd; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("enable_su: copy_from_user failed\n"); + return -EFAULT; + } + + if (cmd.enable == ksu_su_compat_enabled) { + pr_info("enable_su: no need to change\n"); + return 0; + } + + if (cmd.enable) { + ksu_sucompat_init(); + } else { + ksu_sucompat_exit(); + } + + ksu_su_compat_enabled = cmd.enable; + + 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}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + strscpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full)); +#else + 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; + } + + 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 = "Kprobes"; + +#if defined(CONFIG_KSU_TRACEPOINT_HOOK) + type = "Tracepoint"; +#elif defined(CONFIG_KSU_MANUAL_HOOK) + type = "Manual"; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + strscpy(cmd.hook_type, type, sizeof(cmd.hook_type)); +#else + 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; + } + + 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); + + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("enable_kpm: copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int do_dynamic_manager(void __user *arg) +{ + 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; + } + + 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; + } + + return 0; +} + +static int do_get_managers(void __user *arg) +{ + struct ksu_get_managers_cmd cmd; + + 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; + } + + return 0; +} + +static int do_enable_uid_scanner(void __user *arg) +{ + 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; + } + + 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) { + // 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; + } + + return 0; +} + +// IOCTL handlers mapping table +static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = { + { .cmd = KSU_IOCTL_GRANT_ROOT, .handler = do_grant_root, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_GET_INFO, .handler = do_get_info, .perm_check = perm_check_all}, + { .cmd = KSU_IOCTL_REPORT_EVENT, .handler = do_report_event, .perm_check = perm_check_root}, + { .cmd = KSU_IOCTL_SET_SEPOLICY, .handler = do_set_sepolicy, .perm_check = perm_check_root}, + { .cmd = KSU_IOCTL_CHECK_SAFEMODE, .handler = do_check_safemode, .perm_check = perm_check_all}, + { .cmd = KSU_IOCTL_GET_ALLOW_LIST, .handler = do_get_allow_list, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_GET_DENY_LIST, .handler = do_get_deny_list, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .handler = do_uid_granted_root, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .handler = do_uid_should_umount, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_GET_MANAGER_UID, .handler = do_get_manager_uid, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_GET_APP_PROFILE, .handler = do_get_app_profile, .perm_check = perm_check_manager}, + { .cmd = KSU_IOCTL_SET_APP_PROFILE, .handler = do_set_app_profile, .perm_check = perm_check_manager}, + { .cmd = KSU_IOCTL_IS_SU_ENABLED, .handler = do_is_su_enabled, .perm_check = perm_check_manager}, + { .cmd = KSU_IOCTL_ENABLE_SU, .handler = do_enable_su, .perm_check = perm_check_manager}, + { .cmd = KSU_IOCTL_GET_FULL_VERSION, .handler = do_get_full_version, .perm_check = perm_check_manager}, + { .cmd = KSU_IOCTL_HOOK_TYPE, .handler = do_get_hook_type, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_ENABLE_KPM, .handler = do_enable_kpm, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .handler = do_dynamic_manager, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_GET_MANAGERS, .handler = do_get_managers, .perm_check = perm_check_basic}, + { .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .handler = do_enable_uid_scanner, .perm_check = perm_check_basic}, + { .cmd = 0, .handler = NULL, .perm_check = NULL} // Sentinel +}; + +// IOCTL dispatcher +static long anon_ksu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + 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); +#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); + return -EPERM; + } + // Execute handler + return ksu_ioctl_handlers[i].handler(argp); + } + } + + 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; +} + +// 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, +}; + +// Install KSU fd to current process +int ksu_install_fd(void) +{ + 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; + } + + // 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); + + pr_info("ksu fd installed: %d for pid %d\n", fd, current->pid); + + return fd; +} \ No newline at end of file diff --git a/kernel/supercalls.h b/kernel/supercalls.h new file mode 100644 index 00000000..738aef66 --- /dev/null +++ b/kernel/supercalls.h @@ -0,0 +1,142 @@ +#ifndef __KSU_H_SUPERCALLS +#define __KSU_H_SUPERCALLS + +#include +#include +#include "ksu.h" + +// Magic numbers for reboot hook to install fd +#define KSU_INSTALL_MAGIC1 0xDEADBEEF +#define KSU_INSTALL_MAGIC2 0xCAFEBABE + +// Command structures for ioctl + +struct ksu_become_daemon_cmd { + __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) +}; + +struct ksu_report_event_cmd { + __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 +}; + +struct ksu_check_safemode_cmd { + __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 +}; + +struct ksu_uid_granted_root_cmd { + __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 +}; + +struct ksu_get_manager_uid_cmd { + __u32 uid; // Output: manager UID +}; + +struct ksu_get_app_profile_cmd { + struct app_profile profile; // Input/Output: app profile structure +}; + +struct ksu_set_app_profile_cmd { + struct app_profile profile; // Input: app profile structure +}; + +struct ksu_is_su_enabled_cmd { + __u8 enabled; // Output: true if su compat enabled +}; + +struct ksu_enable_su_cmd { + __u8 enable; // Input: true to enable, false to disable +}; + +// Other command structures +struct ksu_get_full_version_cmd { + char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string +}; + +struct ksu_hook_type_cmd { + char hook_type[32]; // Output: hook type string +}; + +struct ksu_enable_kpm_cmd { + __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 ksu_get_managers_cmd { + 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) +}; + +// IOCTL command definitions +#define KSU_IOCTL_GRANT_ROOT _IO('K', 1) +#define KSU_IOCTL_GET_INFO _IOR('K', 2, struct ksu_get_info_cmd) +#define KSU_IOCTL_REPORT_EVENT _IOW('K', 3, struct ksu_report_event_cmd) +#define KSU_IOCTL_SET_SEPOLICY _IOWR('K', 4, struct ksu_set_sepolicy_cmd) +#define KSU_IOCTL_CHECK_SAFEMODE _IOR('K', 5, struct ksu_check_safemode_cmd) +#define KSU_IOCTL_GET_ALLOW_LIST _IOWR('K', 6, struct ksu_get_allow_list_cmd) +#define KSU_IOCTL_GET_DENY_LIST _IOWR('K', 7, struct ksu_get_allow_list_cmd) +#define KSU_IOCTL_UID_GRANTED_ROOT _IOWR('K', 8, struct ksu_uid_granted_root_cmd) +#define KSU_IOCTL_UID_SHOULD_UMOUNT _IOWR('K', 9, struct ksu_uid_should_umount_cmd) +#define KSU_IOCTL_GET_MANAGER_UID _IOR('K', 10, struct ksu_get_manager_uid_cmd) +#define KSU_IOCTL_GET_APP_PROFILE _IOWR('K', 11, struct ksu_get_app_profile_cmd) +#define KSU_IOCTL_SET_APP_PROFILE _IOW('K', 12, struct ksu_set_app_profile_cmd) +#define KSU_IOCTL_IS_SU_ENABLED _IOR('K', 13, struct ksu_is_su_enabled_cmd) +#define KSU_IOCTL_ENABLE_SU _IOW('K', 14, struct ksu_enable_su_cmd) +// Other IOCTL command definitions +#define KSU_IOCTL_GET_FULL_VERSION _IOR('K', 100, struct ksu_get_full_version_cmd) +#define KSU_IOCTL_HOOK_TYPE _IOR('K', 101, struct ksu_hook_type_cmd) +#define KSU_IOCTL_ENABLE_KPM _IOR('K', 102, struct ksu_enable_kpm_cmd) +#define KSU_IOCTL_DYNAMIC_MANAGER _IOWR('K', 103, struct ksu_dynamic_manager_cmd) +#define KSU_IOCTL_GET_MANAGERS _IOWR('K', 104, struct ksu_get_managers_cmd) +#define KSU_IOCTL_ENABLE_UID_SCANNER _IOWR('K', 105, struct ksu_enable_uid_scanner_cmd) + +// IOCTL handler types +typedef int (*ksu_ioctl_handler_t)(void __user *arg); +typedef bool (*ksu_perm_check_t)(void); + +// Permission check functions +bool perm_check_manager(void); +bool perm_check_root(void); +bool perm_check_basic(void); +bool perm_check_all(void); + +// IOCTL command mapping +struct ksu_ioctl_cmd_map { + unsigned int cmd; + ksu_ioctl_handler_t handler; + ksu_perm_check_t perm_check; // Permission check function +}; + +// Install KSU fd to current process +int ksu_install_fd(void); + +#endif // __KSU_H_SUPERCALLS \ No newline at end of file diff --git a/kernel/throne_comm.c b/kernel/throne_comm.c index e79da9b8..d6b99ff3 100644 --- a/kernel/throne_comm.c +++ b/kernel/throne_comm.c @@ -4,6 +4,7 @@ #include #include #include +#include "ksu.h" #include "klog.h" #include "throne_comm.h" @@ -18,198 +19,196 @@ static struct work_struct scan_work; static struct work_struct ksu_state_save_work; static struct work_struct ksu_state_load_work; -extern bool ksu_uid_scanner_enabled; - // Signal userspace to rescan static bool need_rescan = false; static void rescan_work_fn(struct work_struct *work) { - // Signal userspace through proc interface - need_rescan = true; - pr_info("requested userspace uid rescan\n"); + // 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) { - 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 d1bf3383..3266d026 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -435,6 +435,9 @@ void track_throne(void) __maybe_unused loff_t pos = 0; __maybe_unused loff_t line_start = 0; __maybe_unused char buf[KSU_MAX_PACKAGE_NAME]; + static bool manager_exist = false; + static bool dynamic_manager_exist = false; + static int current_manager_uid = ksu_get_manager_uid() % 100000; // init uid list head INIT_LIST_HEAD(&uid_list); @@ -501,9 +504,6 @@ void track_throne(void) uid_ready: // first, check if manager_uid exist! - bool manager_exist = false; - int current_manager_uid = ksu_get_manager_uid() % 100000; - list_for_each_entry(np, &uid_list, list) { if (np->uid == current_manager_uid) { manager_exist = true; @@ -519,7 +519,6 @@ uid_ready: } // Check if the Dynamic Manager exists (only check locked UIDs) - bool dynamic_manager_exist = false; if (ksu_is_dynamic_manager_enabled() && locked_dynamic_manager_uid != KSU_INVALID_UID) { list_for_each_entry(np, &uid_list, list) { diff --git a/kernel/throne_tracker_legacy.c b/kernel/throne_tracker_legacy.c index f244f219..cb32bf43 100644 --- a/kernel/throne_tracker_legacy.c +++ b/kernel/throne_tracker_legacy.c @@ -21,220 +21,220 @@ uid_t ksu_manager_uid = KSU_INVALID_UID; #define KSU_UID_LIST_PATH "/data/misc/user_uid/uid_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 whitelist first, fallback if failed static int read_uid_whitelist(struct list_head *uid_list) { - struct file *fp; - char *file_content = NULL; - char *line, *next_line; - loff_t file_size; - loff_t pos = 0; - int count = 0; - ssize_t bytes_read; - - fp = ksu_filp_open_compat(KSU_UID_LIST_PATH, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_info("whitelist not found, fallback needed\n"); - return -ENOENT; - } + struct file *fp; + char *file_content = NULL; + char *line, *next_line; + loff_t file_size; + loff_t pos = 0; + int count = 0; + ssize_t bytes_read; + + fp = ksu_filp_open_compat(KSU_UID_LIST_PATH, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_info("whitelist not found, fallback needed\n"); + return -ENOENT; + } - file_size = fp->f_inode->i_size; - if (file_size <= 0) { - pr_info("whitelist file is empty\n"); - filp_close(fp, NULL); - return -ENODATA; - } + file_size = fp->f_inode->i_size; + if (file_size <= 0) { + pr_info("whitelist file is empty\n"); + filp_close(fp, NULL); + return -ENODATA; + } - file_content = kzalloc(file_size + 1, GFP_ATOMIC); - if (!file_content) { - pr_err("failed to allocate memory for whitelist file (%lld bytes)\n", file_size); - filp_close(fp, NULL); - return -ENOMEM; - } + file_content = kzalloc(file_size + 1, GFP_ATOMIC); + if (!file_content) { + pr_err("failed to allocate memory for whitelist file (%lld bytes)\n", file_size); + filp_close(fp, NULL); + return -ENOMEM; + } - bytes_read = ksu_kernel_read_compat(fp, file_content, file_size, &pos); - if (bytes_read != file_size) { - pr_err("failed to read whitelist file: read %zd bytes, expected %lld bytes\n", - bytes_read, file_size); - kfree(file_content); - filp_close(fp, NULL); - return -EIO; - } + bytes_read = ksu_kernel_read_compat(fp, file_content, file_size, &pos); + if (bytes_read != file_size) { + pr_err("failed to read whitelist file: read %zd bytes, expected %lld bytes\n", + bytes_read, file_size); + kfree(file_content); + filp_close(fp, NULL); + return -EIO; + } - file_content[file_size] = '\0'; - filp_close(fp, NULL); + file_content[file_size] = '\0'; + filp_close(fp, NULL); - pr_info("successfully read whitelist file (%lld bytes), parsing lines...\n", file_size); + pr_info("successfully read whitelist file (%lld bytes), parsing lines...\n", file_size); - line = file_content; - while (line && *line) { - next_line = strchr(line, '\n'); - if (next_line) { - *next_line = '\0'; - next_line++; - } + line = file_content; + while (line && *line) { + next_line = strchr(line, '\n'); + if (next_line) { + *next_line = '\0'; + next_line++; + } - char *trimmed_line = line; - while (*trimmed_line == ' ' || *trimmed_line == '\t' || *trimmed_line == '\r') { - trimmed_line++; - } + char *trimmed_line = line; + while (*trimmed_line == ' ' || *trimmed_line == '\t' || *trimmed_line == '\r') { + trimmed_line++; + } - if (strlen(trimmed_line) > 0) { - char *line_copy = trimmed_line; - char *uid_str = strsep(&line_copy, " \t"); - char *package_name = line_copy; - - if (package_name) { - while (*package_name == ' ' || *package_name == '\t') { - package_name++; - } - } - - if (uid_str && package_name && strlen(package_name) > 0) { - u32 uid; - if (!kstrtou32(uid_str, 10, &uid)) { - struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC); - if (data) { - data->uid = uid; - size_t pkg_len = strlen(package_name); - size_t copy_len = min(pkg_len, (size_t)(KSU_MAX_PACKAGE_NAME - 1)); - strncpy(data->package, package_name, copy_len); - data->package[copy_len] = '\0'; - - list_add_tail(&data->list, uid_list); - count++; - - if (count % 100 == 0) { - pr_info("parsed %d packages so far...\n", count); - } - } else { - pr_err("failed to allocate memory for uid_data\n"); - } - } else { - pr_warn("invalid uid format in line: %s\n", trimmed_line); - } - } else { - pr_warn("invalid line format: %s\n", trimmed_line); - } - } + if (strlen(trimmed_line) > 0) { + char *line_copy = trimmed_line; + char *uid_str = strsep(&line_copy, " \t"); + char *package_name = line_copy; + + if (package_name) { + while (*package_name == ' ' || *package_name == '\t') { + package_name++; + } + } + + if (uid_str && package_name && strlen(package_name) > 0) { + u32 uid; + if (!kstrtou32(uid_str, 10, &uid)) { + struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC); + if (data) { + data->uid = uid; + size_t pkg_len = strlen(package_name); + size_t copy_len = min(pkg_len, (size_t)(KSU_MAX_PACKAGE_NAME - 1)); + strncpy(data->package, package_name, copy_len); + data->package[copy_len] = '\0'; + + list_add_tail(&data->list, uid_list); + count++; + + if (count % 100 == 0) { + pr_info("parsed %d packages so far...\n", count); + } + } else { + pr_err("failed to allocate memory for uid_data\n"); + } + } else { + pr_warn("invalid uid format in line: %s\n", trimmed_line); + } + } else { + pr_warn("invalid line format: %s\n", trimmed_line); + } + } - line = next_line; - } - - kfree(file_content); - pr_info("successfully loaded %d uids from whitelist\n", count); - return count > 0 ? 0 : -ENODATA; + line = next_line; + } + + kfree(file_content); + pr_info("successfully loaded %d uids from whitelist\n", count); + return count > 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) + 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 list_head *list = (struct list_head *)uid_data; - struct uid_data *np; + struct list_head *list = (struct list_head *)uid_data; + struct uid_data *np; - list_for_each_entry(np, list, list) { - if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) { - pr_info("Crowning manager: %s(uid=%d, signature_index=%d)\n", - pkg, np->uid, signature_index); + list_for_each_entry(np, list, list) { + if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) { + pr_info("Crowning manager: %s(uid=%d, signature_index=%d)\n", + pkg, np->uid, signature_index); - // Dynamic Sign index (1) or multi-manager signatures (2+) - if (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2) { - ksu_add_manager(np->uid, signature_index); + // Dynamic Sign index (1) or multi-manager signatures (2+) + if (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2) { + ksu_add_manager(np->uid, signature_index); - if (!ksu_is_manager_uid_valid()) { - ksu_set_manager_uid(np->uid); - } - } else { - ksu_set_manager_uid(np->uid); - } - break; - } - } + if (!ksu_is_manager_uid_valid()) { + ksu_set_manager_uid(np->uid); + } + } else { + ksu_set_manager_uid(np->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; 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. @@ -248,362 +248,362 @@ struct my_dir_context { #define FILLDIR_ACTOR_STOP -EINVAL #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 (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 (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir, + namelen, name) >= DATA_PATH_LEN) { + pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen, + name); + return FILLDIR_ACTOR_CONTINUE; + } - if (d_type == DT_DIR && my_ctx->depth > 0 && - (my_ctx->stop && !*my_ctx->stop)) { - struct data_path *data = - kmalloc(sizeof(struct data_path), GFP_ATOMIC); + if (d_type == DT_DIR && my_ctx->depth > 0 && + (my_ctx->stop && !*my_ctx->stop)) { + struct data_path *data = + kmalloc(sizeof(struct data_path), GFP_ATOMIC); - if (!data) { - pr_err("Failed to allocate memory for %s\n", dirpath); - return FILLDIR_ACTOR_CONTINUE; - } + 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); + pr_info("Found new base.apk at path: %s, is_multi_manager: %d, signature_index: %d\n", + dirpath, is_multi_manager, signature_index); + // Check for dynamic sign or multi-manager signatures + if (is_multi_manager && + (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2)) { + crown_manager(dirpath, my_ctx->private_data, + signature_index); - struct apk_path_hash *apk_data = - kmalloc(sizeof(struct apk_path_hash), - GFP_ATOMIC); + struct apk_path_hash *apk_data = + kmalloc(sizeof(struct apk_path_hash), + GFP_ATOMIC); - if (apk_data) { - apk_data->hash = hash; - apk_data->exists = true; - list_add_tail(&apk_data->list, - &apk_path_hash_list); - } + if (apk_data) { + apk_data->hash = hash; + apk_data->exists = true; + list_add_tail(&apk_data->list, + &apk_path_hash_list); + } - } else if (is_manager_apk(dirpath)) { - crown_manager(dirpath, my_ctx->private_data, 0); - *my_ctx->stop = 1; + } else if (is_manager_apk(dirpath)) { + crown_manager(dirpath, my_ctx->private_data, 0); + *my_ctx->stop = 1; - // Manager found, clear APK cache list - list_for_each_entry_safe( - pos, n, &apk_path_hash_list, list) { - list_del(&pos->list); - kfree(pos); - } - } else { - struct apk_path_hash *apk_data = - kmalloc(sizeof(struct apk_path_hash), - GFP_ATOMIC); - if (apk_data) { - apk_data->hash = hash; - apk_data->exists = true; - list_add_tail(&apk_data->list, - &apk_path_hash_list); - } - } - } - } + // Manager found, clear APK cache list + list_for_each_entry_safe( + pos, n, &apk_path_hash_list, list) { + list_del(&pos->list); + kfree(pos); + } + } else { + struct apk_path_hash *apk_data = + kmalloc(sizeof(struct apk_path_hash), + GFP_ATOMIC); + if (apk_data) { + apk_data->hash = hash; + apk_data->exists = true; + list_add_tail(&apk_data->list, + &apk_path_hash_list); + } + } + } + } - return FILLDIR_ACTOR_CONTINUE; + 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); - INIT_LIST_HEAD(&apk_path_hash_list); - unsigned long data_app_magic = 0; + int i, stop = 0; + struct list_head data_path_list; + INIT_LIST_HEAD(&data_path_list); + INIT_LIST_HEAD(&apk_path_hash_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; - } + // 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); - } + iterate_dir(file, &ctx.ctx); + filp_close(file, NULL); + } skip_iterate: - list_del(&pos->list); - if (pos != &data) - kfree(pos); - } - } + list_del(&pos->list); + if (pos != &data) + kfree(pos); + } + } - // clear apk_path_hash_list unconditionally - pr_info("search manager: cleanup!\n"); - list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { - list_del(&pos->list); - kfree(pos); - } + // clear apk_path_hash_list unconditionally + pr_info("search manager: cleanup!\n"); + list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { + 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(void) { - struct list_head uid_list; - INIT_LIST_HEAD(&uid_list); + struct list_head uid_list; + INIT_LIST_HEAD(&uid_list); - pr_info("track_throne triggered, attempting whitelist read\n"); - - // Try read whitelist first - int ret = read_uid_whitelist(&uid_list); - - if (ret < 0) { - pr_info("whitelist read failed (%d), request userspace scan\n", ret); - - // Request userspace to rescan - ksu_request_userspace_scan(); - - // fallback to packages.list method - struct file *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)); - goto out; - } + pr_info("track_throne triggered, attempting whitelist read\n"); + + // Try read whitelist first + int ret = read_uid_whitelist(&uid_list); + + if (ret < 0) { + pr_info("whitelist read failed (%d), request userspace scan\n", ret); + + // Request userspace to rescan + ksu_request_userspace_scan(); + + // fallback to packages.list method + struct file *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)); + goto out; + } - char chr = 0; - loff_t pos = 0; - loff_t line_start = 0; - char buf[KSU_MAX_PACKAGE_NAME]; - size_t fallback_count = 0; - - for (;;) { - ssize_t count = - ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); - if (count != sizeof(chr)) - break; - if (chr != '\n') - continue; + char chr = 0; + loff_t pos = 0; + loff_t line_start = 0; + char buf[KSU_MAX_PACKAGE_NAME]; + size_t fallback_count = 0; + + 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); + 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; - } + 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"); - kfree(data); - 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"); + kfree(data); + break; + } - u32 res; - if (kstrtou32(uid, 10, &res)) { - pr_err("update_uid: uid parse err\n"); - kfree(data); - break; - } - data->uid = res; - strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); - list_add_tail(&data->list, &uid_list); - fallback_count++; - - // reset line start - line_start = pos; - } - filp_close(fp, 0); - pr_info("Loaded %zu packages from packages.list fallback\n", fallback_count); - } else { - pr_info("loaded uids from whitelist successfully\n"); - } + u32 res; + if (kstrtou32(uid, 10, &res)) { + pr_err("update_uid: uid parse err\n"); + kfree(data); + break; + } + data->uid = res; + strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); + list_add_tail(&data->list, &uid_list); + fallback_count++; + + // reset line start + line_start = pos; + } + filp_close(fp, 0); + pr_info("Loaded %zu packages from packages.list fallback\n", fallback_count); + } else { + pr_info("loaded uids from whitelist successfully\n"); + } - // now update uid list - struct uid_data *np; - struct uid_data *n; + // now update uid list + struct uid_data *np; + struct uid_data *n; - // first, check if manager_uid exist! - bool manager_exist = false; - bool dynamic_manager_exist = false; + // first, check if manager_uid exist! + bool manager_exist = false; + bool dynamic_manager_exist = false; - list_for_each_entry(np, &uid_list, list) { - // if manager is installed in work profile, the uid in packages.list is still equals main profile - // don't delete it in this case! - int manager_uid = ksu_get_manager_uid() % 100000; - if (np->uid == manager_uid) { - manager_exist = true; - break; - } - } + list_for_each_entry(np, &uid_list, list) { + // if manager is installed in work profile, the uid in packages.list is still equals main profile + // don't delete it in this case! + int manager_uid = ksu_get_manager_uid() % 100000; + if (np->uid == manager_uid) { + manager_exist = true; + break; + } + } - // Check for dynamic managers - if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { - list_for_each_entry(np, &uid_list, list) { - // Check if this uid is a dynamic manager (not the traditional manager) - if (ksu_is_any_manager(np->uid) && - np->uid != ksu_get_manager_uid()) { - dynamic_manager_exist = true; - break; - } - } - } + // Check for dynamic managers + if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { + list_for_each_entry(np, &uid_list, list) { + // Check if this uid is a dynamic manager (not the traditional manager) + if (ksu_is_any_manager(np->uid) && + np->uid != ksu_get_manager_uid()) { + dynamic_manager_exist = true; + break; + } + } + } - if (!manager_exist) { - if (ksu_is_manager_uid_valid()) { - pr_info("manager is uninstalled, invalidate it!\n"); - ksu_invalidate_manager_uid(); - goto prune; - } - pr_info("Searching manager...\n"); - search_manager("/data/app", 2, &uid_list); - pr_info("Search manager finished\n"); - } else if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { - // Always perform search when called from dynamic manager rescan - pr_info("Dynamic sign enabled, Searching manager...\n"); - search_manager("/data/app", 2, &uid_list); - pr_info("Search Dynamic sign manager finished\n"); - } + if (!manager_exist) { + if (ksu_is_manager_uid_valid()) { + pr_info("manager is uninstalled, invalidate it!\n"); + ksu_invalidate_manager_uid(); + goto prune; + } + pr_info("Searching manager...\n"); + search_manager("/data/app", 2, &uid_list); + pr_info("Search manager finished\n"); + } else if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { + // Always perform search when called from dynamic manager rescan + pr_info("Dynamic sign enabled, Searching manager...\n"); + search_manager("/data/app", 2, &uid_list); + pr_info("Search Dynamic sign manager 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 }