From 9d2ede6aec22da04734b981348ba34eeab96f18e Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:50:48 +0800 Subject: [PATCH] kernel & KernelSU: Another attempt to optimize SUS_MOUNT and SUS_SU Changes: 1. Simplified the flow of mnt_id reorder, now it happens only after all sus mounts are umounted in ksu_handle_setuid() 2. All mounts mounted by ksu process will be flagged as sus mount and allocated with a fake mnt_id/mnt_group_id during ONLY the post-fs-data and service stage, which means other ksu mounts during/after boot-completed stage will not be handled by susfs. 3. Renaming: - susfs_mnt_id_ida => susfs_ksu_mnt_id_ida - susfs_mnt_group_ida => susfs_ksu_mnt_group_ida - DEFAULT_SUS_MNT_ID => DEFAULT_KSU_MNT_ID - DEFAULT_SUS_MNT_GROUP_ID => DEFAULT_KSU_MNT_GROUP_ID 4. Increased the default fake mnt_id to 300000, and default fake mnt_group_id to 3000. 5. Unify susfs_is_current_non_root_user_app_proc() and susfs_is_current_proc_su_not_allowed() as susfs_is_current_proc_umounted() Unify susfs_set_current_non_root_user_app_proc() and susfs_set_current_proc_su_not_allowed() as susfs_set_current_proc_umounted() Unify TIF_NON_ROOT_USER_APP_PROC and TIF_PROC_SU_NOT_ALLOWED as TIF_PROC_UMOUNTED 6. Removed unused susfs_is_allow_su() 7. Reworked a custom ksu_handle_setuid() which will be used if CONFIG_KSU_SUSFS is defined Co-authored-by: simonpunk --- kernel/core_hook.c | 234 ++++++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 108 deletions(-) diff --git a/kernel/core_hook.c b/kernel/core_hook.c index f64e6a15..e384874b 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -65,15 +65,7 @@ bool ksu_uid_scanner_enabled = false; #ifdef CONFIG_KSU_SUSFS -bool susfs_is_allow_su(void) -{ - if (is_manager()) { - // we are manager, allow! - return true; - } - return ksu_is_allow_uid(current_uid().val); -} - +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 @@ -86,6 +78,7 @@ extern bool susfs_is_log_enabled __read_mostly; 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; @@ -134,6 +127,22 @@ static inline void susfs_on_post_fs_data(void) { 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_module_mounted = false; @@ -645,12 +654,12 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, switch (arg3) { case EVENT_POST_FS_DATA: { static bool post_fs_data_lock = false; -#ifdef CONFIG_KSU_SUSFS - susfs_on_post_fs_data(); -#endif 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(); // Initialize UID scanner if enabled init_uid_scanner(); @@ -665,6 +674,10 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, 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; } @@ -1423,11 +1436,11 @@ static void try_umount(const char *mnt, bool check_mnt, int flags) 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("/system_ext", true, 0, uid); try_umount("/vendor", true, 0, uid); try_umount("/product", true, 0, uid); - try_umount("/odm", 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); @@ -1445,6 +1458,7 @@ void susfs_try_umount_all(uid_t 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! @@ -1464,54 +1478,92 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) return 0; } -#ifdef CONFIG_KSU_SUSFS - // check if current process is zygote - bool is_zygote_child = susfs_is_sid_equal(old->security, susfs_zygote_sid); -#endif // #ifdef CONFIG_KSU_SUSFS - if (likely(is_zygote_child)) { - // if spawned process is non user app process - if (unlikely(new_uid.val < 10000 && new_uid.val >= 1000)) { -#ifdef CONFIG_KSU_SUSFS_SUS_SU - // set flag if zygote spawned system process is allowed for root access - if (!ksu_is_allow_uid(new_uid.val)) { - task_lock(current); - susfs_set_current_proc_su_not_allowed(); - task_unlock(current); - } -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU -#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // umount for the system process if path DATA_ADB_UMOUNT_FOR_ZYGOTE_SYSTEM_PROCESS exists - if (susfs_is_umount_for_zygote_system_process_enabled) { - goto out_try_umount; - } -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - } -#ifdef CONFIG_KSU_SUSFS - // - here we check if uid is a isolated service spawned by zygote directly - // - Apps that do not use "useAppZyogte" to start a isolated service will be directly - // spawned by zygote which KSU will ignore it by default, the only fix for now is to - // force a umount for those uid - // - Therefore make sure your root app doesn't use isolated service for root access - // - Kudos to ThePedroo, the author and maintainer of Rezygisk for finding and reporting - // the detection, really big helps here! - else if (new_uid.val >= 90000 && new_uid.val < 1000000) { - task_lock(current); - susfs_set_current_non_root_user_app_proc(); -#ifdef CONFIG_KSU_SUSFS_SUS_SU - susfs_set_current_proc_su_not_allowed(); -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU - task_unlock(current); -#ifdef CONFIG_KSU_SUSFS_SUS_PATH - susfs_run_sus_path_loop(new_uid.val); -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH -#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (susfs_is_umount_for_zygote_iso_service_enabled) { - goto out_susfs_try_umount_all; - } - #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - } + // We only interest in process spwaned by zygote + if (!susfs_is_sid_equal(old->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.val) && susfs_is_umount_for_zygote_iso_service_enabled) { + goto do_umount; + } + + // Check if spawned process is normal user app and needs to be umounted + if (likely(is_zygote_normal_app_uid(new_uid.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; + } + + 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); +#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); + + // 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 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); + +#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.val); +#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH + 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; + } + + 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; } -#endif // #ifdef CONFIG_KSU_SUSFS 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); @@ -1523,29 +1575,6 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) return 0; } - if (ksu_is_allow_uid(new_uid.val)) { -#ifdef CONFIG_KSU_DEBUG - pr_info("handle setuid ignore allowed application: %d\n", new_uid.val); -#endif - return 0; - } -#ifdef CONFIG_KSU_SUSFS - else { - task_lock(current); - susfs_set_current_non_root_user_app_proc(); -#ifdef CONFIG_KSU_SUSFS_SUS_SU - susfs_set_current_proc_su_not_allowed(); -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU - task_unlock(current); -#ifdef CONFIG_KSU_SUSFS_SUS_PATH - susfs_run_sus_path_loop(new_uid.val); -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH - } -#endif // #ifdef CONFIG_KSU_SUSFS - -#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT -out_try_umount: -#endif if (!ksu_uid_should_umount(new_uid.val)) { return 0; } else { @@ -1553,53 +1582,42 @@ out_try_umount: pr_info("uid: %d should not umount!\n", current_uid().val); #endif } -#ifndef CONFIG_KSU_SUSFS - // 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 = ksu_is_zygote(old->security); -#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; } +#ifdef CONFIG_KSU_DEBUG + // umount the target mnt + pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, + current->pid); +#endif - -#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT -out_susfs_try_umount_all: - // 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 modules path try_umount("/data/adb/modules", false, MNT_DETACH); - // try umount kpm path - try_umount("/data/adb/kpm", 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 hosts file - try_umount("/system/etc/hosts", false, MNT_DETACH); - // try umount lsposed dex2oat bins - try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH); - try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH); -#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) {