#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_KSU_SUSFS #include #endif // #ifdef CONFIG_KSU_SUSFS #ifndef KSU_HAS_PATH_UMOUNT #include // sys_umount (<4.17) & ksys_umount (4.17+) #endif #ifdef MODULE #include #include #include #include #include #endif #include "allowlist.h" #include "setuid_hook.h" #include "feature.h" #include "klog.h" // IWYU pragma: keep #include "ksu.h" #include "manager.h" #include "selinux/selinux.h" #include "seccomp_cache.h" #include "supercalls.h" #ifndef CONFIG_KSU_SUSFS #include "syscall_hook_manager.h" #endif #include "kernel_umount.h" #include "app_profile.h" #include "sulog.h" #ifdef CONFIG_KSU_SUSFS static inline bool is_some_system_uid(uid_t uid) { uid %= 100000; return (uid >= 1000 && uid < 10000); } static inline bool is_zygote_isolated_service_uid(uid_t uid) { uid %= 100000; return (uid >= 90000 && uid < 100000); } static inline bool is_zygote_normal_app_uid(uid_t uid) { uid %= 100000; return (uid >= 10000 && uid < 19999); } bool susfs_is_umount_for_zygote_system_process_enabled = false; extern bool susfs_is_umount_for_zygote_iso_service_enabled; extern u32 susfs_zygote_sid; #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_SUS_MOUNT extern void susfs_reorder_mnt_id(void); #endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT extern void susfs_try_umount_all(void); #endif #endif // #ifdef CONFIG_KSU_SUSFS static bool ksu_enhanced_security_enabled = false; static int enhanced_security_feature_get(u64 *value) { *value = ksu_enhanced_security_enabled ? 1 : 0; return 0; } static int enhanced_security_feature_set(u64 value) { bool enable = value != 0; ksu_enhanced_security_enabled = enable; pr_info("enhanced_security: set to %d\n", enable); return 0; } static const struct ksu_feature_handler enhanced_security_handler = { .feature_id = KSU_FEATURE_ENHANCED_SECURITY, .name = "enhanced_security", .get_handler = enhanced_security_feature_get, .set_handler = enhanced_security_feature_set, }; static inline bool is_allow_su(void) { if (is_manager()) { // we are manager, allow! return true; } return ksu_is_allow_uid_for_current(current_uid().val); } #ifndef 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_setresuid from %d to %d\n", old_uid, new_uid); // if old process is root, ignore it. if (old_uid != 0 && ksu_enhanced_security_enabled) { // disallow any non-ksu domain escalation from non-root to root! // euid is what we care about here as it controls permission if (unlikely(euid == 0)) { if (!is_ksu_domain()) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); force_sig(SIGKILL); return 0; } } // disallow appuid decrease to any other uid if it is not allowed to su if (is_appuid(old_uid)) { if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); force_sig(SIGKILL); return 0; } } return 0; } // if on private space, see if its possibly the manager if (new_uid > PER_USER_RANGE && new_uid % PER_USER_RANGE == ksu_get_manager_uid()) { ksu_set_manager_uid(new_uid); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) if (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); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); ksu_set_task_tracepoint_flag(current); spin_unlock_irq(¤t->sighand->siglock); return 0; } if (ksu_is_allow_uid_for_current(new_uid)) { 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); } ksu_set_task_tracepoint_flag(current); } else { ksu_clear_task_tracepoint_flag_if_needed(current); } #else if (ksu_is_allow_uid_for_current(new_uid)) { spin_lock_irq(¤t->sighand->siglock); disable_seccomp(); spin_unlock_irq(¤t->sighand->siglock); if (ksu_get_manager_uid() == new_uid) { pr_info("install fd for ksu manager(uid=%d)\n", new_uid); ksu_install_fd(); } return 0; } #endif // Handle kernel umount ksu_handle_umount(old_uid, new_uid); return 0; } #else extern bool ksu_kernel_umount_enabled; extern bool ksu_module_mounted; int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){ // we rely on the fact that zygote always call setresuid(3) with same uids uid_t new_uid = ruid; uid_t old_uid = current_uid().val; // if old process is root, ignore it. if (old_uid != 0 && ksu_enhanced_security_enabled) { // disallow any non-ksu domain escalation from non-root to root! // euid is what we care about here as it controls permission if (unlikely(euid == 0)) { if (!is_ksu_domain()) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); force_sig(SIGKILL); return 0; } } // disallow appuid decrease to any other uid if it is not allowed to su if (is_appuid(old_uid)) { if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) { pr_warn("find suspicious EoP: %d %s, from %d to %d\n", current->pid, current->comm, old_uid, new_uid); force_sig(SIGKILL); return 0; } } return 0; } // We only interest in process spwaned by zygote if (!susfs_is_sid_equal(current_cred()->security, susfs_zygote_sid)) { return 0; } #if __SULOG_GATE ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL); #endif // 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 LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) if (ksu_get_manager_uid() == new_uid % 100000) { pr_info("install fd for manager: %d\n", new_uid); 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; } #else if (ksu_is_allow_uid_for_current(new_uid)) { spin_lock_irq(¤t->sighand->siglock); disable_seccomp(); spin_unlock_irq(¤t->sighand->siglock); if (ksu_get_manager_uid() == new_uid) { pr_info("install fd for ksu manager(uid=%d)\n", new_uid); ksu_install_fd(); } return 0; } #endif // Check if spawned process is normal user app and needs to be umounted if (likely(is_zygote_normal_app_uid(new_uid) && ksu_uid_should_umount(new_uid))) { goto do_umount; } // 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 LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) if (ksu_is_allow_uid_for_current(new_uid)) { 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); } } #endif return 0; do_umount: if (!ksu_kernel_umount_enabled || !ksu_module_mounted) { goto skip_try_umount; } #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT pr_info("susfs: running susfs_try_umount_all() for uid: %u\n", new_uid); susfs_try_umount_all(); #endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT skip_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; } #endif // #ifndef CONFIG_KSU_SUSFS void ksu_setuid_hook_init(void) { ksu_kernel_umount_init(); if (ksu_register_feature_handler(&enhanced_security_handler)) { pr_err("Failed to register enhanced security feature handler\n"); } } void ksu_setuid_hook_exit(void) { pr_info("ksu_core_exit\n"); ksu_kernel_umount_exit(); ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY); }