From 4a15864786b235cf45a163505214723aa880a7e6 Mon Sep 17 00:00:00 2001 From: simonpunk <16465163+simonpunk@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:55:27 +0800 Subject: [PATCH] [skip ci]: Import KSU_SUSFS V1.3.8 patches from simonpunk Taken from: https://gitlab.com/simonpunk/susfs4ksu --- kernel/Kconfig | 83 ++++++++++++++++ kernel/Makefile | 39 ++++++++ kernel/core_hook.c | 210 +++++++++++++++++++++++++++++++++++++++++ kernel/kernel_compat.c | 10 ++ kernel/kernel_compat.h | 1 + kernel/ksu.c | 8 ++ kernel/selinux/rules.c | 5 + 7 files changed, 356 insertions(+) diff --git a/kernel/Kconfig b/kernel/Kconfig index 67f177f4708a..1bb1620368a1 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -16,4 +16,87 @@ config KSU_DEBUG help Enable KernelSU debug mode. +menu "KernelSU - SUSFS" +config KSU_SUSFS + bool "KernelSU addon - SUSFS" + depends on KSU + default n + help + Patch and Enable SUSFS to kernel with KernelSU + +config KSU_SUSFS_SUS_PATH + bool "Enable to hide suspicious path" + depends on KSU_SUSFS + default y + help + Allow hiding the existence of user-defined file/directory from various system calls + +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] + +config KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER + bool "Enable to re-order mount id and parent mount id in mountinfo (experimental)" + depends on KSU_SUSFS_SUS_MOUNT + default y + help + - Enable this option will automatically and completely re-order the mount id and parent mount id in /proc/self/mountinfo + - The actual mnt_id/parent_mnt_id is not changed in kernel, only reflects on /proc/self/mountinfo + - You should not enable this if the mnt_id on your device is already not in order by default + - Moreover, be careful this feature may cause unknown system crashes / random reboot / bootloop on different kernels or devices, further testing is needed. + - Requires KSU_SUSFS_SUS_MOUNT to be ON + +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 + +config KSU_SUSFS_SUS_MAPS + bool "Enable to spoof suspicious maps" + depends on KSU_SUSFS + default y + help + Allow spoofing the user-defined mappings in /proc/self/[maps|smaps|map_files] + +config KSU_SUSFS_SUS_PROC_FD_LINK + bool "Enable to spoof suspicous symbolic links (experimental)" + depends on KSU_SUSFS + default y + help + Allow spoofing the user-defined symbolic link in /proc/self/fd/ + +config KSU_SUSFS_SUS_MEMFD + bool "Enable to hide or spoof suspicous memfd (experimental)" + depends on KSU_SUSFS + default y + help + Allow preventing the user-defined memfd name from being created + +config KSU_SUSFS_TRY_UMOUNT + bool "Enable to use ksu's try_umount" + depends on KSU_SUSFS + default y + help + Allow using ksu's umount to umount other user-defined mount paths prior to ksu's default umount paths + +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 + +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 +endmenu + endmenu diff --git a/kernel/Makefile b/kernel/Makefile index 669297563b1d..d25f36c7c154 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -66,4 +66,43 @@ 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 +ifeq ($(shell test -e $(srctree)/fs/susfs.c; echo $$?),0) +ifdef KSU_SUSFS +ccflags-y += -DKSU_SUSFS +endif +ifdef KSU_SUSFS_SUS_PATH +ccflags-y += -DKSU_SUSFS_SUS_PATH +endif +ifdef KSU_SUSFS_SUS_MOUNT +ccflags-y += -DKSU_SUSFS_SUS_MOUNT +endif +ifdef KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER +ccflags-y += -DKSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER +endif +ifdef KSU_SUSFS_SUS_KSTAT +ccflags-y += -DKSU_SUSFS_SUS_KSTAT +endif +ifdef KSU_SUSFS_SUS_MAPS +ccflags-y += -DKSU_SUSFS_SUS_MAPS +endif +ifdef KSU_SUSFS_SUS_PROC_FD_LINK +ccflags-y += -DKSU_SUSFS_SUS_PROC_FD_LINK +endif +ifdef KSU_SUSFS_SUS_MEMFD +ccflags-y += -DKSU_SUSFS_SUS_MEMFD +endif +ifdef KSU_SUSFS_TRY_UMOUNT +ccflags-y += -DKSU_SUSFS_TRY_UMOUNT +endif +ifdef KSU_SUSFS_SPOOF_UNAME +ccflags-y += -DKSU_SUSFS_SPOOF_UNAME +endif +ifdef KSU_SUSFS_ENABLE_LOG +ccflags-y += -DKSU_SUSFS_ENABLE_LOG +endif +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/core_hook.c b/kernel/core_hook.c index 429ba3306ea3..f016db751970 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -44,6 +44,10 @@ #include "throne_tracker.h" #include "kernel_compat.h" +#ifdef CONFIG_KSU_SUSFS +#include +#endif + static bool ksu_module_mounted = false; extern int handle_sepolicy(unsigned long arg3, void __user *arg4); @@ -375,6 +379,207 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } +#ifdef CONFIG_KSU_SUSFS + if (current_uid().val == 0) { + int error = 0; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (arg2 == CMD_SUSFS_ADD_SUS_PATH) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_SUS_PATH +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + if (arg2 == CMD_SUSFS_ADD_SUS_MOUNT) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT + if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } + if (arg2 == CMD_SUSFS_UPDATE_SUS_KSTAT) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } + if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT +#ifdef CONFIG_KSU_SUSFS_SUS_MAPS + if (arg2 == CMD_SUSFS_ADD_SUS_MAPS) { + if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_maps))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_MAPS -> arg3 is not accessible\n"); + return 0; + } + if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_MAPS -> arg5 is not accessible\n"); + return 0; + } + error = susfs_add_sus_maps((struct st_susfs_sus_maps __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_MAPS -> ret: %d\n", error); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } + if (arg2 == CMD_SUSFS_UPDATE_SUS_MAPS) { + if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_maps))) { + pr_err("susfs: CMD_SUSFS_UPDATE_SUS_MAPS -> arg3 is not accessible\n"); + return 0; + } + if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { + pr_err("susfs: CMD_SUSFS_UPDATE_SUS_MAPS -> arg5 is not accessible\n"); + return 0; + } + error = susfs_update_sus_maps((struct st_susfs_sus_maps __user*)arg3); + pr_info("susfs: CMD_SUSFS_UPDATE_SUS_MAPS -> ret: %d\n", error); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } + if (arg2 == CMD_SUSFS_ADD_SUS_MAPS_STATICALLY) { + if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_maps))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_MAPS_STATICALLY -> arg3 is not accessible\n"); + return 0; + } + if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_MAPS_STATICALLY -> arg5 is not accessible\n"); + return 0; + } + error = susfs_add_sus_maps((struct st_susfs_sus_maps __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_MAPS_STATICALLY -> ret: %d\n", error); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MAPS +#ifdef CONFIG_KSU_SUSFS_SUS_PROC_FD_LINK + if (arg2 == CMD_SUSFS_ADD_SUS_PROC_FD_LINK) { + if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_proc_fd_link))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_PROC_FD_LINK -> arg3 is not accessible\n"); + return 0; + } + if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_PROC_FD_LINK -> arg5 is not accessible\n"); + return 0; + } + error = susfs_add_sus_proc_fd_link((struct st_susfs_sus_proc_fd_link __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_PROC_FD_LINK -> ret: %d\n", error); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_SUS_PROC_FD_LINK +#ifdef CONFIG_KSU_SUSFS_SUS_MEMFD + if (arg2 == CMD_SUSFS_ADD_SUS_MEMFD) { + if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_memfd))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_MEMFD -> arg3 is not accessible\n"); + return 0; + } + if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_MEMFD -> arg5 is not accessible\n"); + return 0; + } + error = susfs_add_sus_memfd((struct st_susfs_sus_memfd __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_MEMFD -> ret: %d\n", error); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MEMFD +#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT + if (arg2 == CMD_SUSFS_ADD_TRY_UMOUNT) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT +#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME + if (arg2 == CMD_SUSFS_SET_UNAME) { + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + 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); + copy_to_user((void __user*)arg5, &error, sizeof(error)); + return 0; + } +#endif //#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG + } +#endif //#ifdef CONFIG_KSU_SUSFS + // all other cmds are for 'root manager' if (!from_manager) { return 0; @@ -535,6 +740,11 @@ 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(new_uid.val); +#endif + // 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); diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c index b242bc637398..0ec3df624f94 100644 --- a/kernel/kernel_compat.c +++ b/kernel/kernel_compat.c @@ -77,6 +77,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) diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index ba9981857fd1..34050e73d790 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 3639edc21503..4a9cfaba9f4f 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) @@ -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); diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index 1ba6d853f2a9..7b24203ce0ad 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -134,6 +134,11 @@ 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"); +#endif + rcu_read_unlock(); }