diff --git a/kernel/Makefile b/kernel/Makefile index 8fa60590..e80ebd59 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -97,6 +97,7 @@ ccflags-y += -DKSU_MANUAL_HOOK $(info -- SukiSU: KSU_MANUAL_HOOK) else ccflags-y += -DKSU_HAVE_SYSCALL_TRACEPOINTS_HOOK +ccflags-y += -DKSU_LKM_MODE ccflags-y += -DKSU_KPROBES_HOOK $(info -- SukiSU: KSU_TRACEPOINT_HOOK) endif diff --git a/kernel/kernel_umount.c b/kernel/kernel_umount.c index 13d1b7a3..3e738eeb 100644 --- a/kernel/kernel_umount.c +++ b/kernel/kernel_umount.c @@ -23,11 +23,87 @@ #include "feature.h" #include "ksud.h" +#include "sulog.h" + #ifdef CONFIG_KSU_SUSFS +bool susfs_is_boot_completed_triggered = false; +extern u32 susfs_zygote_sid; extern bool susfs_is_mnt_devname_ksu(struct path *path); +#ifdef CONFIG_KSU_SUSFS_SUS_PATH +extern void susfs_run_sus_path_loop(uid_t uid); +#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH #ifdef CONFIG_KSU_SUSFS_ENABLE_LOG extern bool susfs_is_log_enabled __read_mostly; #endif // #ifdef CONFIG_KSU_SUSFS_ENABLE_LOG +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +static bool susfs_is_umount_for_zygote_system_process_enabled = false; +static bool susfs_is_umount_for_zygote_iso_service_enabled = false; +extern bool susfs_hide_sus_mnts_for_all_procs; +extern void susfs_reorder_mnt_id(void); +#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT +extern bool 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 +extern bool 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 +extern bool susfs_is_auto_add_try_umount_for_bind_mount_enabled; +#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT +#ifdef CONFIG_KSU_SUSFS_SUS_SU +extern bool susfs_is_sus_su_ready; +extern int susfs_sus_su_working_mode; +extern bool susfs_is_sus_su_hooks_enabled __read_mostly; +extern bool ksu_devpts_hook; +#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU + +static inline void susfs_on_post_fs_data(void) { + 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); +#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); +#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); +#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); +#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); +} + +static inline bool is_zygote_isolated_service_uid(uid_t uid) +{ + 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)); +} + #endif // #ifdef CONFIG_KSU_SUSFS static bool ksu_kernel_umount_enabled = true; @@ -274,6 +350,109 @@ static inline bool is_unsupported_uid(uid_t uid) return appid > LAST_APPLICATION_UID; } +#ifdef CONFIG_KSU_SUSFS +int ksu_handle_umount(uid_t old_uid, uid_t new_uid) +{ + struct umount_tw *tw; + + // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it! + if (!ksu_module_mounted) { + return 0; + } + + if (!ksu_kernel_umount_enabled) { + return 0; + } + + if (!is_appuid(new_uid) || is_unsupported_uid(new_uid)) { + pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid); + return 0; + } + + if (!ksu_uid_should_umount(new_uid)) { + return 0; + } else { + pr_info("uid: %d should not umount!\n", current_uid().val); + } + + // We only interest in process spwaned by zygote + if (!susfs_is_sid_equal(current->cred->security, susfs_zygote_sid)) { + 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) && 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 % 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) && ksu_uid_should_umount(new_uid))) { + goto do_umount; + } + + // Lastly, Check if spawned process is some system process and needs to be umounted + if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) { + goto do_umount; + } +#if __SULOG_GATE + ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); +#endif + + 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); +#else + tw = kmalloc(sizeof(*tw), GFP_ATOMIC); + if (!tw) + return 0; + + tw->old_cred = get_current_cred(); + tw->cb.func = umount_tw_func; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) + int err = task_work_add(current, &tw->cb, TWA_RESUME); +#else + int err = task_work_add(current, &tw->cb, true); +#endif + if (err) { + if (tw->old_cred) { + put_cred(tw->old_cred); + } + kfree(tw); + pr_warn("unmount add task_work failed\n"); + } +#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT + + 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(); +#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + + susfs_set_current_proc_umounted(); + + put_task_struct(current); + +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + susfs_run_sus_path_loop(new_uid); +#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH + + return 0; +} +#else int ksu_handle_umount(uid_t old_uid, uid_t new_uid) { struct umount_tw *tw; @@ -306,6 +485,9 @@ int ksu_handle_umount(uid_t old_uid, uid_t new_uid) pr_info("handle umount ignore non zygote child: %d\n", current->pid); return 0; } +#if __SULOG_GATE + ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); +#endif // umount the target mnt pr_info("handle umount for uid: %d, pid: %d\n", new_uid, current->pid); @@ -331,6 +513,7 @@ int ksu_handle_umount(uid_t old_uid, uid_t new_uid) return 0; } +#endif void ksu_kernel_umount_init(void) { diff --git a/kernel/setuid_hook.c b/kernel/setuid_hook.c index 39e95207..e19cdacc 100644 --- a/kernel/setuid_hook.c +++ b/kernel/setuid_hook.c @@ -151,21 +151,6 @@ static inline void susfs_on_post_fs_data(void) { #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); -} - -static inline bool is_zygote_isolated_service_uid(uid_t uid) -{ - 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)); -} - #endif // #ifdef CONFIG_KSU_SUSFS static inline bool is_allow_su(void) @@ -184,6 +169,16 @@ static inline bool is_unsupported_uid(uid_t uid) return appid > LAST_APPLICATION_UID; } +static bool is_appuid(uid_t uid) +{ +#define PER_USER_RANGE 100000 +#define FIRST_APPLICATION_UID 10000 +#define LAST_APPLICATION_UID 19999 + + uid_t appid = uid % PER_USER_RANGE; + return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; +} + #if __SULOG_GATE static void sulog_prctl_cmd(uid_t uid, unsigned long cmd) { @@ -478,167 +473,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } -static bool is_appuid(uid_t uid) -{ -#define PER_USER_RANGE 100000 -#define FIRST_APPLICATION_UID 10000 -#define LAST_APPLICATION_UID 19999 - - uid_t appid = uid % PER_USER_RANGE; - return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; -} - -#ifdef CONFIG_KSU_SUSFS -int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) -{ - uid_t new_uid = ruid; - uid_t old_uid = current_uid().val; - pr_info("handle_setuid from %d to %d\n", old_uid, new_uid); - - if (0 != old_uid) { - // old process is not root, ignore it. - if (ksu_enhanced_security_enabled) { - // disallow any non-ksu domain escalation from non-root to root! - if (unlikely(new_uid) == 0) { - if (!is_ksu_domain()) { - pr_warn("find suspicious EoP: %d %s, from %d to %d\n", - current->pid, current->comm, old_uid, new_uid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) - force_sig(SIGKILL); -#else - force_sig(SIGKILL, current); -#endif - return 0; - } - } - // disallow appuid decrease to any other uid if it is allowed to su - if (is_appuid(old_uid)) { - if (new_uid < old_uid && !ksu_is_allow_uid_for_current(old_uid)) { - pr_warn("find suspicious EoP: %d %s, from %d to %d\n", - current->pid, current->comm, old_uid, new_uid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) - force_sig(SIGKILL); -#else - force_sig(SIGKILL, current); -#endif - return 0; - } - } - } - return 0; - } - - if (new_uid == 2000) { - ksu_set_task_tracepoint_flag(current); - } - - if (!is_appuid(new_uid) || is_unsupported_uid(new_uid)) { - pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid); - ksu_clear_task_tracepoint_flag(current); - return 0; - } - - // if on private space, see if its possibly the manager - if (unlikely(new_uid > 100000 && new_uid % 100000 == ksu_get_manager_uid())) { - ksu_set_manager_uid(new_uid); - } - - if (unlikely(ksu_get_manager_uid() == new_uid)) { - pr_info("install fd for manager: %d\n", new_uid); - ksu_install_fd(); - spin_lock_irq(¤t->sighand->siglock); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2 - ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); -#else - // we dont have those new fancy things upstream has - // lets just do original thing where we disable seccomp - disable_seccomp(); -#endif - ksu_set_task_tracepoint_flag(current); - spin_unlock_irq(¤t->sighand->siglock); - return 0; - } - - if (unlikely(ksu_is_allow_uid_for_current(new_uid))) { - if (current->seccomp.mode == SECCOMP_MODE_FILTER && - current->seccomp.filter) { - spin_lock_irq(¤t->sighand->siglock); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2 - ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); -#else - // we don't have those new fancy things upstream has - // lets just do original thing where we disable seccomp - disable_seccomp(); -#endif - spin_unlock_irq(¤t->sighand->siglock); - } - ksu_set_task_tracepoint_flag(current); - } else { - ksu_clear_task_tracepoint_flag(current); - } - - // Handle kernel umount - - // We only interest in process spwaned by zygote - if (!susfs_is_sid_equal(current->cred->security, susfs_zygote_sid)) { - 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) && 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 belongs to - // ksu manager - if (ksu_is_manager_uid_valid() && - (new_uid % 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) && ksu_uid_should_umount(new_uid))) { - goto do_umount; - } - - // Lastly, Check if spawned process is some system process and needs to be umounted - if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) { - goto do_umount; - } -#if __SULOG_GATE - ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); -#endif - - 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); -#else - ksu_handle_umount(old_uid, new_uid); - -#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT - - 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(); -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - - susfs_set_current_proc_umounted(); - - put_task_struct(current); - -#ifdef CONFIG_KSU_SUSFS_SUS_PATH - susfs_run_sus_path_loop(new_uid); -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH - return 0; -} -#else int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) { uid_t new_uid = ruid; @@ -721,15 +555,9 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) // Handle kernel umount ksu_handle_umount(old_uid, new_uid); - -#if __SULOG_GATE - ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); -#endif 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) diff --git a/kernel/sucompat.c b/kernel/sucompat.c index eb36b094..3d2ae33c 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -353,35 +353,3 @@ void ksu_sucompat_exit() { ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT); } - -#ifdef CONFIG_KSU_SUSFS_SUS_SU -extern bool ksu_su_compat_enabled; -bool ksu_devpts_hook = false; -bool susfs_is_sus_su_hooks_enabled __read_mostly = false; -int susfs_sus_su_working_mode = 0; - -static bool ksu_is_su_kps_enabled(void) { - 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; - } -} - -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; -} -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU \ No newline at end of file diff --git a/kernel/syscall_hook_manager.c b/kernel/syscall_hook_manager.c index a29bc2c3..979bd44e 100644 --- a/kernel/syscall_hook_manager.c +++ b/kernel/syscall_hook_manager.c @@ -315,11 +315,12 @@ static inline void ksu_handle_task_alloc(struct pt_regs *regs) #endif } -#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK +#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS // Generic sys_enter handler that dispatches to specific handlers static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id) { if (unlikely(check_syscall_fastpath(id))) { +#ifdef KSU_LKM_MODE if (ksu_su_compat_enabled) { // Handle newfstatat if (id == __NR_newfstatat) { @@ -355,6 +356,7 @@ static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id) return; } } +#endif // Handle setresuid if (id == __NR_setresuid) { @@ -394,7 +396,7 @@ void ksu_syscall_hook_manager_init(void) syscall_unregfunc_rp = init_kretprobe("syscall_unregfunc", syscall_unregfunc_handler); #endif -#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK +#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS ret = register_trace_sys_enter(ksu_sys_enter_handler, NULL); #ifndef CONFIG_KRETPROBES unmark_all_process(); @@ -414,7 +416,7 @@ void ksu_syscall_hook_manager_init(void) void ksu_syscall_hook_manager_exit(void) { pr_info("hook_manager: ksu_hook_manager_exit called\n"); -#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK +#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS unregister_trace_sys_enter(ksu_sys_enter_handler, NULL); tracepoint_synchronize_unregister(); pr_info("hook_manager: sys_enter tracepoint unregistered\n");