diff --git a/.github/workflows/fireasf.yml b/.github/workflows/fireasf.yml index 9085a0d63..8a7dbd784 100644 --- a/.github/workflows/fireasf.yml +++ b/.github/workflows/fireasf.yml @@ -26,9 +26,9 @@ jobs: rm -rf setup.sh* rm -rf KernelSU* curl -LSs "https://raw.githubusercontent.com/rifsxd/KernelSU-Next/next/kernel/setup.sh" | bash -s next - cp $(pwd)/patches/0001-KernelSU-Next-Implement-SUSFS-v1.5.3-plus-GKI.patch $(pwd)/KernelSU-Next/0001-KernelSU-Next-Implement-SUSFS-v1.5.3-plus-GKI.patch + cp $(pwd)/patches/Implement-SUSFS-v1.5.4-for-KernelSU-Next.patch $(pwd)/KernelSU-Next/Implement-SUSFS-v1.5.4-for-KernelSU-Next.patch cd $(pwd)/KernelSU-Next/ - patch -p1 < 0001-KernelSU-Next-Implement-SUSFS-v1.5.3-plus-GKI.patch + patch -p1 < Implement-SUSFS-v1.5.4-for-KernelSU-Next.patch cd .. echo "Applied susfs4ksu" export FIREASF_VANILLA=true diff --git a/patches/.gitkeep b/patches/.gitkeep new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/patches/.gitkeep @@ -0,0 +1 @@ + diff --git a/patches/Implement-SUSFS-v1.5.4-for-KernelSU-Next.patch b/patches/Implement-SUSFS-v1.5.4-for-KernelSU-Next.patch new file mode 100644 index 000000000..573cd2d66 --- /dev/null +++ b/patches/Implement-SUSFS-v1.5.4-for-KernelSU-Next.patch @@ -0,0 +1,1528 @@ +From 2dfb17ff9e59395b2914d6d4dc4749b6b4ed3e9e Mon Sep 17 00:00:00 2001 +From: sidex15 <24408329+sidex15@users.noreply.github.com> +Date: Mon, 27 Jan 2025 16:38:46 +0800 +Subject: [PATCH 1/1] Kernel: Implement SUSFS v1.5.4 Universal + +--- + .gitignore | 3 + + kernel/Kconfig | 144 ++++++++++++ + kernel/Makefile | 62 +++++ + kernel/allowlist.c | 10 +- + kernel/apk_sign.c | 2 +- + kernel/apk_sign.h | 2 +- + kernel/core_hook.c | 495 +++++++++++++++++++++++++++++++++++++-- + kernel/kernel_compat.c | 10 + + kernel/kernel_compat.h | 1 + + kernel/ksu.c | 16 +- + kernel/ksud.c | 23 +- + kernel/ksud.h | 2 +- + kernel/manager.h | 2 +- + kernel/selinux/rules.c | 16 +- + kernel/selinux/selinux.c | 95 +++++++- + kernel/selinux/selinux.h | 24 +- + kernel/sucompat.c | 52 +++- + kernel/throne_tracker.c | 4 +- + kernel/throne_tracker.h | 2 +- + 19 files changed, 905 insertions(+), 60 deletions(-) + +diff --git a/.gitignore b/.gitignore +index 706fd07f..e38b0406 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,2 +1,5 @@ + .idea + .vscode ++*.patch ++*.rej ++*.orig +diff --git a/kernel/Kconfig b/kernel/Kconfig +index 1f3802f6..c16b2e30 100644 +--- a/kernel/Kconfig ++++ b/kernel/Kconfig +@@ -24,4 +24,148 @@ config KSU_ALLOWLIST_WORKAROUND + Enable session keyring init workaround for problematic devices. + Useful for situations where the SU allowlist is not kept after a reboot. + ++menu "KernelSU - SUSFS" ++config KSU_SUSFS ++ bool "KernelSU addon - SUSFS" ++ depends on KSU ++ default y ++ help ++ Patch and Enable SUSFS to kernel with KernelSU. ++ ++config KSU_SUSFS_HAS_MAGIC_MOUNT ++ bool "Say yes if the current KernelSU repo has magic mount implemented (default n)" ++ depends on KSU ++ default y ++ help ++ - Enable to indicate that the current SUSFS kernel supports the auto hide features for 5ec1cff's Magic Mount KernelSU ++ - Every mounts from /debug_ramdisk/workdir will be treated as magic mount and processed differently by susfs ++ ++config KSU_SUSFS_SUS_PATH ++ bool "Enable to hide suspicious path (NOT recommended)" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow hiding the user-defined path and all its sub-paths from various system calls. ++ - tmpfs filesystem is not allowed to be added. ++ - Effective only on zygote spawned user app process. ++ - Use with cautious as it may cause performance loss and will be vulnerable to side channel attacks, ++ just disable this feature if it doesn't work for you or you don't need it at all. ++ ++config KSU_SUSFS_SUS_MOUNT ++ bool "Enable to hide suspicious mounts" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow hiding the user-defined mount paths from /proc/self/[mounts|mountinfo|mountstat]. ++ - Effective on all processes for hiding mount entries. ++ - Mounts mounted by process with ksu domain will be forced to be assigned the dev name "KSU". ++ - mnt_id and mnt_group_id of the sus mount will be assigned to a much bigger number to solve the issue of id not being contiguous. ++ ++config KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT ++ bool "Enable to hide KSU's default mounts automatically (experimental)" ++ depends on KSU_SUSFS_SUS_MOUNT ++ default y ++ help ++ - Automatically add KSU's default mounts to sus_mount. ++ - No susfs command is needed in userspace. ++ - Only mount operation from process with ksu domain will be checked. ++ ++config KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT ++ bool "Enable to hide suspicious bind mounts automatically (experimental)" ++ depends on KSU_SUSFS_SUS_MOUNT ++ default y ++ help ++ - Automatically add binded mounts to sus_mount. ++ - No susfs command is needed in userspace. ++ - Only mount operation from process with ksu domain will be checked. ++ ++config KSU_SUSFS_SUS_KSTAT ++ bool "Enable to spoof suspicious kstat" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow spoofing the kstat of user-defined file/directory. ++ - Effective only on zygote spawned user app process. ++ ++config KSU_SUSFS_SUS_OVERLAYFS ++ bool "Enable to automatically spoof kstat and kstatfs for overlayed files/directories" ++ depends on KSU_SUSFS ++ default n ++ help ++ - Automatically spoof the kstat and kstatfs for overlayed files/directories. ++ - Enable it if you are using legacy KernelSU and dont have auto hide features enabled. ++ - No susfs command is needed in userspace. ++ - Effective on all processes. ++ ++config KSU_SUSFS_TRY_UMOUNT ++ bool "Enable to use ksu's ksu_try_umount" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow using ksu_try_umount to umount other user-defined mount paths prior to ksu's default umount paths. ++ - Effective on all NO-root-access-granted processes. ++ ++config KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT ++ bool "Enable to add bind mounts to ksu's ksu_try_umount automatically (experimental)" ++ depends on KSU_SUSFS_TRY_UMOUNT ++ default y ++ help ++ - Automatically add binded mounts to ksu's ksu_try_umount. ++ - No susfs command is needed in userspace. ++ - Only mount operation from process with ksu domain will be checked. ++ ++config KSU_SUSFS_SPOOF_UNAME ++ bool "Enable to spoof uname" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow spoofing the string returned by uname syscall to user-defined string. ++ - Effective on all processes. ++ ++config KSU_SUSFS_ENABLE_LOG ++ bool "Enable logging susfs log to kernel" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow logging susfs log to kernel, uncheck it to completely disable all susfs log. ++ ++config KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS ++ bool "Enable to automatically hide ksu and susfs symbols from /proc/kallsyms" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Automatically hide ksu and susfs symbols from '/proc/kallsyms'. ++ - Effective on all processes. ++ ++config KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG ++ bool "Enable to spoof /proc/bootconfig (gki) or /proc/cmdline (non-gki)" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Spoof the output of /proc/bootconfig (gki) or /proc/cmdline (non-gki) with a user-defined file. ++ - Effective on all processes. ++ ++config KSU_SUSFS_OPEN_REDIRECT ++ bool "Enable to redirect a path to be opened with another path (experimental)" ++ depends on KSU_SUSFS ++ default y ++ help ++ - Allow redirecting a target path to be opened with another user-defined path. ++ - Effective only on processes with uid < 2000. ++ - Please be reminded that process with open access to the target and redirected path can be detected. ++ ++config KSU_SUSFS_SUS_SU ++ bool "Enable SUS-SU in runtime temporarily" ++ depends on KSU_SUSFS && KPROBES && HAVE_KPROBES && KPROBE_EVENTS ++ default y ++ help ++ - Allow user to enable or disable core ksu kprobes hooks temporarily in runtime. There are 2 working modes for sus_su. ++ - Mode 0 (default): Disable sus_su, and enable ksu kprobe hooks for su instead. ++ - Mode 1 (deprecated): ++ - Mode 2: Enable sus_su, and disable ksu kprobe hooks for su, which means the kernel inline hooks are enabled, ++ the same as the su implementaion of non-gki kernel without kprobe supported. ++ - Only apps with root access granted by ksu manager are allowed to get root. ++ ++endmenu ++ + endmenu +diff --git a/kernel/Makefile b/kernel/Makefile +index 9a35b3bf..d147c447 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -138,4 +138,66 @@ endif + ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat + ccflags-y += -Wno-declaration-after-statement -Wno-unused-function + ++## For non-gki compatiblity ## ++ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) ++ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID ++endif ++ ++ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0) ++ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE ++endif ++ ++ccflags-y += -DKSU_UMOUNT ++ifneq ($(shell grep -Eq "^static int can_umount" $(srctree)/fs/namespace.c; echo $$?),0) ++$(info -- KSU_SUSFS: adding function 'static int can_umount(const struct path *path, int flags);' to $(srctree)/fs/namespace.c) ++CAN_UMOUNT = static int can_umount(const struct path *path, int flags)\n\ ++{\n\t\ ++ struct mount *mnt = real_mount(path->mnt);\n\t\ ++ if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))\n\t\t\ ++ return -EINVAL;\n\t\ ++ if (!may_mount())\n\t\t\ ++ return -EPERM;\n\t\ ++ if (path->dentry != path->mnt->mnt_root)\n\t\t\ ++ return -EINVAL;\n\t\ ++ if (!check_mnt(mnt))\n\t\t\ ++ return -EINVAL;\n\t\ ++ if (mnt->mnt.mnt_flags & MNT_LOCKED)\n\t\t\ ++ return -EINVAL;\n\t\ ++ if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))\n\t\t\ ++ return -EPERM;\n\t\ ++ return 0;\n\ ++}\n ++$(shell sed -i '/^static bool is_mnt_ns_file/i $(CAN_UMOUNT)' $(srctree)/fs/namespace.c;) ++endif ++ ++ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/namespace.c; echo $$?),0) ++$(info -- KSU_SUSFS: adding function 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/namespace.c) ++PATH_UMOUNT = int path_umount(struct path *path, int flags)\n\ ++{\n\t\ ++ struct mount *mnt = real_mount(path->mnt);\n\t\ ++ int ret;\n\t\ ++ ret = can_umount(path, flags);\n\t\ ++ if (!ret)\n\t\t\ ++ ret = do_umount(mnt, flags);\n\t\ ++ dput(path->dentry);\n\t\ ++ mntput_no_expire(mnt);\n\t\ ++ return ret;\n\ ++}\n ++$(shell sed -i '/^static bool is_mnt_ns_file/i $(PATH_UMOUNT)' $(srctree)/fs/namespace.c;) ++endif ++ ++ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/internal.h; echo $$?),0) ++$(shell sed -i '/^extern void __init mnt_init/a int path_umount(struct path *path, int flags);' $(srctree)/fs/internal.h;) ++$(info -- KSU_SUSFS: adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h) ++endif ++ ++## For susfs stuff ## ++ifeq ($(shell test -e $(srctree)/fs/susfs.c; echo $$?),0) ++$(eval SUSFS_VERSION=$(shell cat $(srctree)/include/linux/susfs.h | grep -E '^#define SUSFS_VERSION' | cut -d' ' -f3 | sed 's/"//g')) ++$(info ) ++$(info -- SUSFS_VERSION: $(SUSFS_VERSION)) ++else ++$(info -- You have not integrate susfs in your kernel.) ++$(info -- Read: https://gitlab.com/simonpunk/susfs4ksu) ++endif + # Keep a new line here!! Because someone may append config +diff --git a/kernel/allowlist.c b/kernel/allowlist.c +index 443ce430..42c44f64 100644 +--- a/kernel/allowlist.c ++++ b/kernel/allowlist.c +@@ -95,7 +95,7 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE); + static struct work_struct ksu_save_work; + static struct work_struct ksu_load_work; + +-bool persistent_allow_list(void); ++static bool persistent_allow_list(void); + + void ksu_show_allow_list(void) + { +@@ -270,7 +270,7 @@ bool __ksu_is_allow_uid(uid_t uid) + + if (unlikely(uid == 0)) { + // already root, but only allow our domain. +- return is_ksu_domain(); ++ return ksu_is_ksu_domain(); + } + + if (forbid_system_uid(uid)) { +@@ -355,7 +355,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow) + return true; + } + +-void do_save_allow_list(struct work_struct *work) ++static void do_save_allow_list(struct work_struct *work) + { + u32 magic = FILE_MAGIC; + u32 version = FILE_FORMAT_VERSION; +@@ -397,7 +397,7 @@ exit: + filp_close(fp, 0); + } + +-void do_load_allow_list(struct work_struct *work) ++static void do_load_allow_list(struct work_struct *work) + { + loff_t off = 0; + ssize_t ret = 0; +@@ -487,7 +487,7 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data + } + + // make sure allow list works cross boot +-bool persistent_allow_list(void) ++static bool persistent_allow_list(void) + { + return ksu_queue_work(&ksu_save_work); + } +diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c +index 384bb1c5..87401814 100644 +--- a/kernel/apk_sign.c ++++ b/kernel/apk_sign.c +@@ -314,7 +314,7 @@ module_param_cb(ksu_debug_manager_uid, &expected_size_ops, + + #endif + +-bool is_manager_apk(char *path) ++bool ksu_is_manager_apk(char *path) + { + return check_v2_signature(path, EXPECTED_NEXT_SIZE, EXPECTED_NEXT_HASH); + } +\ No newline at end of file +diff --git a/kernel/apk_sign.h b/kernel/apk_sign.h +index bed501c4..e02aa514 100644 +--- a/kernel/apk_sign.h ++++ b/kernel/apk_sign.h +@@ -3,6 +3,6 @@ + + #include + +-bool is_manager_apk(char *path); ++bool ksu_is_manager_apk(char *path); + + #endif +diff --git a/kernel/core_hook.c b/kernel/core_hook.c +index 8694838d..b3fa3dcb 100644 +--- a/kernel/core_hook.c ++++ b/kernel/core_hook.c +@@ -33,6 +33,10 @@ + #include + #endif + ++#ifdef CONFIG_KSU_SUSFS ++#include ++#endif // #ifdef CONFIG_KSU_SUSFS ++ + #include "allowlist.h" + #include "arch.h" + #include "core_hook.h" +@@ -49,13 +53,79 @@ + #define KSU_GET_CRED_RCU + #endif + ++#ifdef CONFIG_KSU_SUSFS ++bool susfs_is_allow_su(void) ++{ ++ if (ksu_is_manager()) { ++ // we are manager, allow! ++ return true; ++ } ++ return ksu_is_allow_uid(current_uid().val); ++} ++ ++extern u32 susfs_zygote_sid; ++extern bool susfs_is_mnt_devname_ksu(struct path *path); ++ ++#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT ++extern void susfs_run_try_umount_for_current_mnt_ns(void); ++#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++static bool susfs_is_umount_for_zygote_system_process_enabled = false; ++#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 ++ ++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 ++} ++#endif // #ifdef CONFIG_KSU_SUSFS ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++extern bool susfs_is_sus_su_ready; ++#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU ++ + static bool ksu_module_mounted = false; + +-extern int handle_sepolicy(unsigned long arg3, void __user *arg4); ++extern int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4); + + static inline bool is_allow_su() + { +- if (is_manager()) { ++ if (ksu_is_manager()) { + // we are manager, allow! + return true; + } +@@ -132,7 +202,7 @@ static void disable_seccomp(void) + #endif + } + +-void escape_to_root(void) ++void ksu_escape_to_root(void) + { + struct cred *cred; + +@@ -201,7 +271,7 @@ void escape_to_root(void) + disable_seccomp(); + spin_unlock_irq(¤t->sighand->siglock); + +- setup_selinux(profile->selinux_domain); ++ ksu_setup_selinux(profile->selinux_domain); + } + + int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) +@@ -238,7 +308,7 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) + pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname, + new_dentry->d_iname, buf); + +- track_throne(); ++ ksu_track_throne(); + + return 0; + } +@@ -263,7 +333,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, + } + + bool from_root = 0 == current_uid().val; +- bool from_manager = is_manager(); ++ bool from_manager = ksu_is_manager(); + + if (!from_root && !from_manager) { + // only root or manager can access this interface +@@ -287,7 +357,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, + if (arg2 == CMD_GRANT_ROOT) { + if (is_allow_su()) { + pr_info("allow root for: %d\n", current_uid().val); +- escape_to_root(); ++ ksu_escape_to_root(); + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("grant_root: prctl reply error\n"); + } +@@ -319,10 +389,13 @@ 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"); +- on_post_fs_data(); ++ ksu_on_post_fs_data(); + } + break; + } +@@ -349,7 +422,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, + if (!from_root) { + return 0; + } +- if (!handle_sepolicy(arg3, arg4)) { ++ if (!ksu_handle_sepolicy(arg3, arg4)) { + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("sepolicy: prctl reply error\n"); + } +@@ -410,6 +483,338 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, + return 0; + } + ++#ifdef CONFIG_KSU_SUSFS ++ if (current_uid_val == 0) { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (arg2 == CMD_SUSFS_ADD_SUS_PATH) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_path))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_add_sus_path((struct st_susfs_sus_path __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_mount))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_add_sus_mount((struct st_susfs_sus_mount __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_kstat))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++ if (arg2 == CMD_SUSFS_UPDATE_SUS_KSTAT) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_kstat))) { ++ pr_err("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_update_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++ if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_kstat))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_try_umount))) { ++ pr_err("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_add_try_umount((struct st_susfs_try_umount __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++ if (arg2 == CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS) { ++ int error = 0; ++ susfs_run_try_umount_for_current_mnt_ns(); ++ pr_info("susfs: CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS -> ret: %d\n", error); ++ } ++#endif //#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT ++#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME ++ if (arg2 == CMD_SUSFS_SET_UNAME) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_uname))) { ++ pr_err("susfs: CMD_SUSFS_SET_UNAME -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SET_UNAME -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_set_uname((struct st_susfs_uname __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_SET_UNAME -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ 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, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, SUSFS_FAKE_CMDLINE_OR_BOOTCONFIG_SIZE)) { ++ pr_err("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_set_cmdline_or_bootconfig((char __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_open_redirect))) { ++ pr_err("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_add_open_redirect((struct st_susfs_open_redirect __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ 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) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_sus_su))) { ++ pr_err("susfs: CMD_SUSFS_SUS_SU -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SUS_SU -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = susfs_sus_su((struct st_sus_su __user*)arg3); ++ pr_info("susfs: CMD_SUSFS_SUS_SU -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++#endif //#ifdef CONFIG_KSU_SUSFS_SUS_SU ++ if (arg2 == CMD_SUSFS_SHOW_VERSION) { ++ int error = 0; ++ int len_of_susfs_version = strlen(SUSFS_VERSION); ++ char *susfs_version = SUSFS_VERSION; ++ if (!ksu_access_ok((void __user*)arg3, len_of_susfs_version+1)) { ++ pr_err("susfs: CMD_SUSFS_SHOW_VERSION -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SHOW_VERSION -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = copy_to_user((void __user*)arg3, (void*)susfs_version, len_of_susfs_version+1); ++ pr_info("susfs: CMD_SUSFS_SHOW_VERSION -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++ if (arg2 == CMD_SUSFS_SHOW_ENABLED_FEATURES) { ++ int error = 0; ++ u64 enabled_features = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(u64))) { ++ pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg5 is not accessible\n"); ++ return 0; ++ } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ enabled_features |= (1 << 0); ++#endif ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ enabled_features |= (1 << 1); ++#endif ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT ++ enabled_features |= (1 << 2); ++#endif ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT ++ enabled_features |= (1 << 3); ++#endif ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++ enabled_features |= (1 << 4); ++#endif ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++ enabled_features |= (1 << 5); ++#endif ++#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT ++ enabled_features |= (1 << 6); ++#endif ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT ++ enabled_features |= (1 << 7); ++#endif ++#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME ++ enabled_features |= (1 << 8); ++#endif ++#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG ++ enabled_features |= (1 << 9); ++#endif ++#ifdef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS ++ enabled_features |= (1 << 10); ++#endif ++#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG ++ enabled_features |= (1 << 11); ++#endif ++#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT ++ enabled_features |= (1 << 12); ++#endif ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++ enabled_features |= (1 << 13); ++#endif ++#ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT ++ enabled_features |= (1 << 14); ++#endif ++ error = copy_to_user((void __user*)arg3, (void*)&enabled_features, sizeof(enabled_features)); ++ pr_info("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++ if (arg2 == CMD_SUSFS_SHOW_VARIANT) { ++ int error = 0; ++ int len_of_variant = strlen(SUSFS_VARIANT); ++ char *susfs_variant = SUSFS_VARIANT; ++ if (!ksu_access_ok((void __user*)arg3, len_of_variant+1)) { ++ pr_err("susfs: CMD_SUSFS_SHOW_VARIANT -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SHOW_VARIANT -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = copy_to_user((void __user*)arg3, (void*)susfs_variant, len_of_variant+1); ++ pr_info("susfs: CMD_SUSFS_SHOW_VARIANT -> ret: %d\n", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++ if (arg2 == CMD_SUSFS_IS_SUS_SU_READY) { ++ int error = 0; ++ if (!ksu_access_ok((void __user*)arg3, sizeof(susfs_is_sus_su_ready))) { ++ pr_err("susfs: CMD_SUSFS_IS_SUS_SU_READY -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_IS_SUS_SU_READY -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = 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", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++ if (arg2 == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) { ++ int error = 0; ++ int working_mode = susfs_get_sus_su_working_mode(); ++ if (!ksu_access_ok((void __user*)arg3, sizeof(working_mode))) { ++ pr_err("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> arg3 is not accessible\n"); ++ return 0; ++ } ++ if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { ++ pr_err("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> arg5 is not accessible\n"); ++ return 0; ++ } ++ error = 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", error); ++ if (copy_to_user((void __user*)arg5, &error, sizeof(error))) ++ pr_info("susfs: copy_to_user() failed\n"); ++ return 0; ++ } ++#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU ++ } ++#endif //#ifdef CONFIG_KSU_SUSFS ++ + // all other cmds are for 'root manager' + if (!from_manager) { + return 0; +@@ -477,11 +882,15 @@ static bool should_umount(struct path *path) + return false; + } + ++#ifdef CONFIG_KSU_SUSFS ++ 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; ++#endif + } + + static int ksu_umount_mnt(struct path *path, int flags) +@@ -494,7 +903,7 @@ static int ksu_umount_mnt(struct path *path, int flags) + #endif + } + +-static void try_umount(const char *mnt, bool check_mnt, int flags) ++void ksu_try_umount(const char *mnt, bool check_mnt, int flags) + { + struct path path; + int err = kern_path(mnt, 0, &path); +@@ -518,6 +927,23 @@ static void try_umount(const char *mnt, bool check_mnt, int flags) + } + } + ++#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT ++void susfs_try_umount_all(uid_t uid) { ++ susfs_try_umount(uid); ++ /* For Legacy KSU only */ ++ ksu_try_umount("/system", true, 0); ++ ksu_try_umount("/system_ext", true, 0); ++ ksu_try_umount("/vendor", true, 0); ++ ksu_try_umount("/product", true, 0); ++ ksu_try_umount("/odm", true, 0); ++ // - 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 ++ ksu_try_umount("/data/adb/modules", false, MNT_DETACH); ++ /* For both Legacy KSU and Magic Mount KSU */ ++ ksu_try_umount("/debug_ramdisk", true, MNT_DETACH); ++} ++#endif ++ + 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! +@@ -537,6 +963,20 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) + return 0; + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // check if current process is zygote ++ bool is_zygote_child = susfs_is_sid_equal(old->security, susfs_zygote_sid); ++ if (likely(is_zygote_child)) { ++ // if spawned process is non user app process ++ if (unlikely(new_uid.val < 10000 && new_uid.val >= 1000)) { ++ // 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_ksu_try_umount; ++ } ++ } ++ } ++#endif ++ + 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; +@@ -546,7 +986,17 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) + // pr_info("handle setuid ignore allowed application: %d\n", new_uid.val); + return 0; + } ++#ifdef CONFIG_KSU_SUSFS ++ else { ++ task_lock(current); ++ current->susfs_task_state |= TASK_STRUCT_NON_ROOT_USER_APP_PROC; ++ task_unlock(current); ++ } ++#endif + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++out_ksu_try_umount: ++#endif + if (!ksu_uid_should_umount(new_uid.val)) { + return 0; + } else { +@@ -555,10 +1005,12 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) + #endif + } + ++#ifndef CONFIG_KSU_SUSFS_SUS_MOUNT + // 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); ++ bool is_zygote_child = ksu_is_zygote(old->security); ++#endif + if (!is_zygote_child) { + pr_info("handle umount ignore non zygote child: %d\n", + current->pid); +@@ -570,20 +1022,25 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) + current->pid); + #endif + ++#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("/system", true, 0); +- try_umount("/system_ext", true, 0); +- try_umount("/vendor", true, 0); +- try_umount("/product", true, 0); +- try_umount("/data/adb/modules", false, MNT_DETACH); ++ ksu_try_umount("/system", true, 0); ++ ksu_try_umount("/system_ext", true, 0); ++ ksu_try_umount("/vendor", true, 0); ++ ksu_try_umount("/product", true, 0); ++ ksu_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); ++ ksu_try_umount("/debug_ramdisk", false, MNT_DETACH); ++ ksu_try_umount("/sbin", false, MNT_DETACH); + + // try umount hosts file +- try_umount("/system/etc/hosts", false, MNT_DETACH); ++ ksu_try_umount("/system/etc/hosts", false, MNT_DETACH); ++#endif + + return 0; + } +diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c +index a1886433..f898707e 100644 +--- a/kernel/kernel_compat.c ++++ b/kernel/kernel_compat.c +@@ -76,6 +76,16 @@ void ksu_android_ns_fs_check() + task_unlock(current); + } + ++int ksu_access_ok(const void *addr, unsigned long size) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) ++ /* For kernels before 5.0.0, pass the type argument to access_ok. */ ++ return access_ok(VERIFY_READ, addr, size); ++#else ++ /* For kernels 5.0.0 and later, ignore the type argument. */ ++ return access_ok(addr, size); ++#endif ++} ++ + 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) +diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h +index 6d79f7ed..b0d664a9 100644 +--- a/kernel/kernel_compat.h ++++ b/kernel/kernel_compat.h +@@ -29,6 +29,7 @@ extern struct key *init_session_keyring; + #endif + + extern void ksu_android_ns_fs_check(); ++extern int ksu_access_ok(const void *addr, unsigned long size); + extern struct file *ksu_filp_open_compat(const char *filename, int flags, + umode_t mode); + extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, +diff --git a/kernel/ksu.c b/kernel/ksu.c +index 3639edc2..b6dc8681 100644 +--- a/kernel/ksu.c ++++ b/kernel/ksu.c +@@ -11,6 +11,10 @@ + #include "ksu.h" + #include "throne_tracker.h" + ++#ifdef CONFIG_KSU_SUSFS ++#include ++#endif ++ + static struct workqueue_struct *ksu_workqueue; + + bool ksu_queue_work(struct work_struct *work) +@@ -37,7 +41,7 @@ extern void ksu_sucompat_exit(); + extern void ksu_ksud_init(); + extern void ksu_ksud_exit(); + +-int __init kernelsu_init(void) ++int __init ksu_kernelsu_init(void) + { + #ifdef CONFIG_KSU_DEBUG + pr_alert("*************************************************************"); +@@ -49,6 +53,10 @@ int __init kernelsu_init(void) + pr_alert("*************************************************************"); + #endif + ++#ifdef CONFIG_KSU_SUSFS ++ susfs_init(); ++#endif ++ + ksu_core_init(); + + ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0); +@@ -72,7 +80,7 @@ int __init kernelsu_init(void) + return 0; + } + +-void kernelsu_exit(void) ++void ksu_kernelsu_exit(void) + { + ksu_allowlist_exit(); + +@@ -88,8 +96,8 @@ void kernelsu_exit(void) + ksu_core_exit(); + } + +-module_init(kernelsu_init); +-module_exit(kernelsu_exit); ++module_init(ksu_kernelsu_init); ++module_exit(ksu_kernelsu_exit); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("weishu"); +diff --git a/kernel/ksud.c b/kernel/ksud.c +index 68e47352..16040f3f 100644 +--- a/kernel/ksud.c ++++ b/kernel/ksud.c +@@ -64,17 +64,22 @@ bool ksu_execveat_hook __read_mostly = true; + bool ksu_input_hook __read_mostly = true; + #endif + ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++bool ksu_devpts_hook = false; ++bool susfs_is_sus_su_ready = false; ++#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU ++ + u32 ksu_devpts_sid; + +-void on_post_fs_data(void) ++void ksu_on_post_fs_data(void) + { + static bool done = false; + if (done) { +- pr_info("on_post_fs_data already done\n"); ++ pr_info("ksu_on_post_fs_data already done\n"); + return; + } + done = true; +- pr_info("on_post_fs_data!\n"); ++ pr_info("ksu_on_post_fs_data!\n"); + ksu_load_allow_list(); + // sanity check, this may influence the performance + stop_input_hook(); +@@ -197,7 +202,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, + first_arg); + if (!strcmp(first_arg, "second_stage")) { + pr_info("/system/bin/init second_stage executed\n"); +- apply_kernelsu_rules(); ++ ksu_apply_kernelsu_rules(); + init_second_stage_executed = true; + ksu_android_ns_fs_check(); + } +@@ -221,7 +226,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, + pr_info("/init first arg: %s\n", first_arg); + if (!strcmp(first_arg, "--second-stage")) { + pr_info("/init second_stage executed\n"); +- apply_kernelsu_rules(); ++ ksu_apply_kernelsu_rules(); + init_second_stage_executed = true; + ksu_android_ns_fs_check(); + } +@@ -258,7 +263,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, + (!strcmp(env_value, "1") || + !strcmp(env_value, "true"))) { + pr_info("/init second_stage executed\n"); +- apply_kernelsu_rules(); ++ ksu_apply_kernelsu_rules(); + init_second_stage_executed = + true; + ksu_android_ns_fs_check(); +@@ -273,7 +278,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, + first_app_process = false; + pr_info("exec app_process, /data prepared, second_stage: %d\n", + init_second_stage_executed); +- on_post_fs_data(); // we keep this for old ksud ++ ksu_on_post_fs_data(); // we keep this for old ksud + stop_execve_hook(); + } + +@@ -616,6 +621,10 @@ static void stop_execve_hook() + ksu_execveat_hook = false; + pr_info("stop execve_hook\n"); + #endif ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++ susfs_is_sus_su_ready = true; ++ pr_info("susfs: sus_su is ready\n"); ++#endif + } + + static void stop_input_hook() +diff --git a/kernel/ksud.h b/kernel/ksud.h +index cc2df243..26974c9c 100644 +--- a/kernel/ksud.h ++++ b/kernel/ksud.h +@@ -5,7 +5,7 @@ + + #define KSUD_PATH "/data/adb/ksud" + +-void on_post_fs_data(void); ++void ksu_on_post_fs_data(void); + + bool ksu_is_safe_mode(void); + +diff --git a/kernel/manager.h b/kernel/manager.h +index be5bbced..93fa2678 100644 +--- a/kernel/manager.h ++++ b/kernel/manager.h +@@ -13,7 +13,7 @@ static inline bool ksu_is_manager_uid_valid() + return ksu_manager_uid != KSU_INVALID_UID; + } + +-static inline bool is_manager() ++static inline bool ksu_is_manager() + { + return unlikely(ksu_manager_uid == current_uid().val); + } +diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c +index 1ba6d853..e4c65106 100644 +--- a/kernel/selinux/rules.c ++++ b/kernel/selinux/rules.c +@@ -36,9 +36,9 @@ static struct policydb *get_policydb(void) + return db; + } + +-void apply_kernelsu_rules() ++void ksu_apply_kernelsu_rules() + { +- if (!getenforce()) { ++ if (!ksu_getenforce()) { + pr_info("SELinux permissive or disabled, apply rules!\n"); + } + +@@ -134,6 +134,14 @@ void apply_kernelsu_rules() + ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid"); + ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill"); + ++#ifdef CONFIG_KSU_SUSFS ++ // Allow umount in zygote process without installing zygisk ++ ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount"); ++ susfs_set_init_sid(); ++ susfs_set_ksu_sid(); ++ susfs_set_zygote_sid(); ++#endif ++ + rcu_read_unlock(); + } + +@@ -195,13 +203,13 @@ static void reset_avc_cache() + selinux_xfrm_notify_policyload(); + } + +-int handle_sepolicy(unsigned long arg3, void __user *arg4) ++int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4) + { + if (!arg4) { + return -1; + } + +- if (!getenforce()) { ++ if (!ksu_getenforce()) { + pr_info("SELinux permissive or disabled when handle policy!\n"); + } + +diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c +index 4ba20b04..e171e010 100644 +--- a/kernel/selinux/selinux.c ++++ b/kernel/selinux/selinux.c +@@ -8,6 +8,14 @@ + + #define KERNEL_SU_DOMAIN "u:r:su:s0" + ++#ifdef CONFIG_KSU_SUSFS ++#define KERNEL_INIT_DOMAIN "u:r:init:s0" ++#define KERNEL_ZYGOTE_DOMAIN "u:r:zygote:s0" ++u32 susfs_ksu_sid = 0; ++u32 susfs_init_sid = 0; ++u32 susfs_zygote_sid = 0; ++#endif ++ + static int transive_to_domain(const char *domain) + { + struct cred *cred; +@@ -37,7 +45,7 @@ static int transive_to_domain(const char *domain) + return error; + } + +-void setup_selinux(const char *domain) ++void ksu_setup_selinux(const char *domain) + { + if (transive_to_domain(domain)) { + pr_err("transive domain failed.\n"); +@@ -52,7 +60,7 @@ if (!is_domain_permissive) { + }*/ + } + +-void setenforce(bool enforce) ++void ksu_setenforce(bool enforce) + { + #ifdef CONFIG_SECURITY_SELINUX_DEVELOP + #ifdef KSU_COMPAT_USE_SELINUX_STATE +@@ -63,7 +71,7 @@ void setenforce(bool enforce) + #endif + } + +-bool getenforce() ++bool ksu_getenforce() + { + #ifdef CONFIG_SECURITY_SELINUX_DISABLE + #ifdef KSU_COMPAT_USE_SELINUX_STATE +@@ -99,7 +107,7 @@ static inline u32 current_sid(void) + } + #endif + +-bool is_ksu_domain() ++bool ksu_is_ksu_domain() + { + char *domain; + u32 seclen; +@@ -113,7 +121,7 @@ bool is_ksu_domain() + return result; + } + +-bool is_zygote(void *sec) ++bool ksu_is_zygote(void *sec) + { + struct task_security_struct *tsec = (struct task_security_struct *)sec; + if (!tsec) { +@@ -131,6 +139,83 @@ bool is_zygote(void *sec) + 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; ++ } ++ ++ 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; ++} ++ ++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 susfs_get_current_sid(void) { ++ return current_sid(); ++} ++ ++void susfs_set_zygote_sid(void) ++{ ++ susfs_set_sid(KERNEL_ZYGOTE_DOMAIN, &susfs_zygote_sid); ++} ++ ++bool susfs_is_current_zygote_domain(void) { ++ return unlikely(current_sid() == susfs_zygote_sid); ++} ++ ++void susfs_set_ksu_sid(void) ++{ ++ susfs_set_sid(KERNEL_SU_DOMAIN, &susfs_ksu_sid); ++} ++ ++bool susfs_is_current_ksu_domain(void) { ++ return unlikely(current_sid() == susfs_ksu_sid); ++} ++ ++void susfs_set_init_sid(void) ++{ ++ susfs_set_sid(KERNEL_INIT_DOMAIN, &susfs_init_sid); ++} ++ ++bool susfs_is_current_init_domain(void) { ++ return unlikely(current_sid() == susfs_init_sid); ++} ++#endif ++ + #define DEVPTS_DOMAIN "u:object_r:ksu_file:s0" + + u32 ksu_get_devpts_sid() +diff --git a/kernel/selinux/selinux.h b/kernel/selinux/selinux.h +index 07120c25..d0dfdf9c 100644 +--- a/kernel/selinux/selinux.h ++++ b/kernel/selinux/selinux.h +@@ -8,17 +8,29 @@ + #define KSU_COMPAT_USE_SELINUX_STATE + #endif + +-void setup_selinux(const char *); ++void ksu_setup_selinux(const char *); + +-void setenforce(bool); ++void ksu_setenforce(bool); + +-bool getenforce(); ++bool ksu_getenforce(); + +-bool is_ksu_domain(); ++bool ksu_is_ksu_domain(); + +-bool is_zygote(void *cred); ++bool ksu_is_zygote(void *cred); + +-void apply_kernelsu_rules(); ++void ksu_apply_kernelsu_rules(); ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++bool susfs_is_sid_equal(void *sec, u32 sid2); ++u32 susfs_get_sid_from_name(const char *secctx_name); ++u32 susfs_get_current_sid(void); ++void susfs_set_zygote_sid(void); ++bool susfs_is_current_zygote_domain(void); ++void susfs_set_ksu_sid(void); ++bool susfs_is_current_ksu_domain(void); ++void susfs_set_init_sid(void); ++bool susfs_is_current_init_domain(void); ++#endif + + u32 ksu_get_devpts_sid(); + +diff --git a/kernel/sucompat.c b/kernel/sucompat.c +index 9b45cd0d..71924c8a 100644 +--- a/kernel/sucompat.c ++++ b/kernel/sucompat.c +@@ -24,7 +24,7 @@ + #define SU_PATH "/system/bin/su" + #define SH_PATH "/system/bin/sh" + +-extern void escape_to_root(); ++extern void ksu_escape_to_root(); + + static void __user *userspace_stack_buffer(const void *d, size_t len) + { +@@ -70,6 +70,31 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, + 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) { ++ // const char sh[] = SH_PATH; ++ const char su[] = SU_PATH; ++ struct filename *name = getname_flags(*filename_user, getname_statx_lookup_flags(*flags), NULL); ++ ++ if (unlikely(IS_ERR(name) || name->name == NULL)) { ++ return name; ++ } ++ ++ if (!ksu_is_allow_uid(current_uid().val)) { ++ return name; ++ } ++ ++ if (likely(memcmp(name->name, su, sizeof(su)))) { ++ return name; ++ } ++ ++ const char sh[] = SH_PATH; ++ pr_info("vfs_fstatat su->sh!\n"); ++ memcpy((void *)name->name, sh, sizeof(sh)); ++ return name; ++} ++#endif ++ + int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) + { + // const char sh[] = SH_PATH; +@@ -136,7 +161,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, + pr_info("do_execveat_common su found\n"); + memcpy((void *)filename->name, sh, sizeof(sh)); + +- escape_to_root(); ++ ksu_escape_to_root(); + + return 0; + } +@@ -163,7 +188,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, + pr_info("sys_execve su found\n"); + *filename_user = ksud_user_path(); + +- escape_to_root(); ++ ksu_escape_to_root(); + + return 0; + } +@@ -365,3 +390,24 @@ void ksu_sucompat_exit() + unregister_kprobe(&pts_unix98_lookup_kp); + #endif + } ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++extern bool ksu_devpts_hook; ++ ++void ksu_susfs_disable_sus_su(void) { ++ enable_kprobe(&execve_kp); ++ enable_kprobe(&newfstatat_kp); ++ enable_kprobe(&faccessat_kp); ++ enable_kprobe(&pts_unix98_lookup_kp); ++ ksu_devpts_hook = false; ++} ++ ++void ksu_susfs_enable_sus_su(void) { ++ disable_kprobe(&execve_kp); ++ disable_kprobe(&newfstatat_kp); ++ disable_kprobe(&faccessat_kp); ++ disable_kprobe(&pts_unix98_lookup_kp); ++ ksu_devpts_hook = true; ++} ++#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU ++ +diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c +index 725c9103..e7ae295e 100644 +--- a/kernel/throne_tracker.c ++++ b/kernel/throne_tracker.c +@@ -182,7 +182,7 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, + } + } + +- bool is_manager = is_manager_apk(dirpath); ++ bool is_manager = ksu_is_manager_apk(dirpath); + pr_info("Found new base.apk at path: %s, is_manager: %d\n", + dirpath, is_manager); + if (is_manager) { +@@ -278,7 +278,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data) + return exist; + } + +-void track_throne() ++void ksu_track_throne() + { + struct file *fp = + ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); +diff --git a/kernel/throne_tracker.h b/kernel/throne_tracker.h +index 5d7f4770..428c737d 100644 +--- a/kernel/throne_tracker.h ++++ b/kernel/throne_tracker.h +@@ -5,6 +5,6 @@ void ksu_throne_tracker_init(); + + void ksu_throne_tracker_exit(); + +-void track_throne(); ++void ksu_track_throne(); + + #endif +-- +2.43.0 +