diff --git a/arch/arm64/configs/vendor/lavender-perf_defconfig b/arch/arm64/configs/vendor/lavender-perf_defconfig index 45943039151c..c052a4e7805f 100644 --- a/arch/arm64/configs/vendor/lavender-perf_defconfig +++ b/arch/arm64/configs/vendor/lavender-perf_defconfig @@ -850,3 +850,4 @@ CONFIG_PANIC_TIMEOUT=-1 CONFIG_RCU_PANIC_ON_STALL=1 # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_AUDIT=y diff --git a/drivers/Kconfig b/drivers/Kconfig index 9625df26d10f..0e232d67f860 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -230,4 +230,5 @@ source "drivers/sensors/Kconfig" source "drivers/gpu/msm/Kconfig" source "drivers/energy_model/Kconfig" +source "drivers/kernelsu/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 0ef73d017b00..a1fbe19a2214 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -192,3 +192,5 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_SENSORS_SSC) += sensors/ + +obj-$(CONFIG_KSU) += kernelsu/ diff --git a/drivers/kernelsu/Kconfig b/drivers/kernelsu/Kconfig index 14d3e854547f..640560371ab7 100644 --- a/drivers/kernelsu/Kconfig +++ b/drivers/kernelsu/Kconfig @@ -49,14 +49,6 @@ config KSU_SUSFS 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 y)" - 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 @@ -105,19 +97,19 @@ config KSU_SUSFS_SUS_KSTAT - Effective only on zygote spawned user app process. config KSU_SUSFS_TRY_UMOUNT - bool "Enable to use ksu's ksu_try_umount" + bool "Enable to use ksu's 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. + - Allow using 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)" + bool "Enable to add bind mounts to ksu's try_umount automatically (experimental)" depends on KSU_SUSFS_TRY_UMOUNT default y help - - Automatically add binded mounts to ksu's ksu_try_umount. + - Automatically add binded mounts to ksu's try_umount. - No susfs command is needed in userspace. - Only mount operation from process with ksu domain will be checked. diff --git a/drivers/kernelsu/Makefile b/drivers/kernelsu/Makefile index 6c1c7bb2bfe6..ee0e827b3d9c 100644 --- a/drivers/kernelsu/Makefile +++ b/drivers/kernelsu/Makefile @@ -16,9 +16,27 @@ ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm- obj-$(CONFIG_KSU) += kernelsu.o -$(eval KSU_VERSION=12803) +ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0) +KSU_VERSION_TAG := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git describe --tags --abbrev=0 2>/dev/null) +$(info -- KernelSU-Next tag: $(KSU_VERSION_TAG)) +ccflags-y += -DKSU_VERSION_TAG=\"$(KSU_VERSION_TAG)\" +else +$(warning "KSU_VERSION_TAG not defined! It is better to make KernelSU-Next a git submodule!") +ccflags-y += -DKSU_VERSION_TAG=\"v0.0.0\" +endif + +# .git is a text file while the module is imported by 'git submodule add'. +ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0) +$(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin [ -f ../.git/shallow ] && git fetch --unshallow) +KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD) +# ksu_version: major * 10000 + git version + 200 for historical reasons +$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 199)) $(info -- KernelSU-Next version: $(KSU_VERSION)) ccflags-y += -DKSU_VERSION=$(KSU_VERSION) +else # If there is no .git file, the default version will be passed. +$(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU-Next a git submodule!") +ccflags-y += -DKSU_VERSION=11998 +endif ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID @@ -40,6 +58,10 @@ ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q " ccflags-y += -DKSU_KERNEL_WRITE endif +ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_flags"; echo $$?),0) +ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR +endif + ifndef KSU_NEXT_MANAGER_SIZE KSU_NEXT_MANAGER_SIZE := 0x3e6 endif @@ -104,6 +126,12 @@ $(shell sed -i '/^extern void __init mnt_init/a int path_umount(struct path *pat $(info -- KSU_NEXT: adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h) endif +ifneq ($(shell grep -q "atomic_t filter_count;" $(srctree)/include/linux/seccomp.h; echo $$?),0) +$(info -- KSU_NEXT: patching struct seccomp for filter_count) +$(shell sed -i '/int mode;/a\ atomic_t filter_count;' $(srctree)/include/linux/seccomp.h) +$(shell sed -i '/#include /a\#include ' $(srctree)/include/linux/seccomp.h) +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 @@ -181,7 +209,7 @@ $(eval SUSFS_VERSION=$(shell cat $(srctree)/include/linux/susfs.h | grep -E '^#d $(info ) $(info -- SUSFS_VERSION: $(SUSFS_VERSION)) else -$(info -- You have not integrate susfs in your kernel.) +$(info -- You have not integrated susfs in your kernel yet.) $(info -- Read: https://gitlab.com/simonpunk/susfs4ksu) endif # Keep a new line here!! Because someone may append config diff --git a/drivers/kernelsu/allowlist.c b/drivers/kernelsu/allowlist.c index 6f2557c9704e..c59be97ca8dd 100644 --- a/drivers/kernelsu/allowlist.c +++ b/drivers/kernelsu/allowlist.c @@ -266,7 +266,7 @@ bool __ksu_is_allow_uid(uid_t uid) if (unlikely(uid == 0)) { // already root, but only allow our domain. - return ksu_is_ksu_domain(); + return is_ksu_domain(); } if (forbid_system_uid(uid)) { diff --git a/drivers/kernelsu/apk_sign.c b/drivers/kernelsu/apk_sign.c index 1c758d72e3de..421096485bd2 100644 --- a/drivers/kernelsu/apk_sign.c +++ b/drivers/kernelsu/apk_sign.c @@ -5,14 +5,15 @@ #include #include #include +#ifdef CONFIG_KSU_DEBUG #include +#endif #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) #include #else #include #endif - #include "apk_sign.h" #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" @@ -314,80 +315,13 @@ static struct kernel_param_ops expected_size_ops = { module_param_cb(ksu_debug_manager_uid, &expected_size_ops, &ksu_debug_manager_uid, S_IRUSR | S_IWUSR); -#else - -static int set_expected_size(const char *val, const struct kernel_param *kp) -{ - int rv = param_set_uint(val, kp); - pr_info("expected_manager_size set to %u\n", expected_manager_size); - return rv; -} - -static int get_expected_size(char *buf, const struct kernel_param *kp) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", expected_manager_size); -} - -static int set_expected_hash(const char *val, const struct kernel_param *kp) -{ - if (strlen(val) != SHA256_DIGEST_SIZE * 2) { - pr_err("Invalid hash length: %s\n", val); - return -EINVAL; - } - - strncpy(expected_manager_hash, val, SHA256_DIGEST_SIZE * 2); - expected_manager_hash[SHA256_DIGEST_SIZE * 2] = '\0'; - - pr_info("expected_manager_hash set to %s\n", expected_manager_hash); - return 0; -} - -static int get_expected_hash(char *buf, const struct kernel_param *kp) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", expected_manager_hash); -} - -static struct kernel_param_ops expected_size_ops = { - .set = set_expected_size, - .get = get_expected_size, -}; - -static struct kernel_param_ops expected_hash_ops = { - .set = set_expected_hash, - .get = get_expected_hash, -}; - -module_param_cb(expected_manager_size, &expected_size_ops, &expected_manager_size, 0644); - -module_param_cb(expected_manager_hash, &expected_hash_ops, &expected_manager_hash, 0644); - #endif -bool ksu_is_manager_apk(char *path) +bool is_manager_apk(char *path) { - int tries = 0; - - while (tries++ < 10) { - if (!is_lock_held(path)) - break; - - pr_info("%s: waiting for %s\n", __func__, path); - msleep(100); - } - - // let it go, if retry fails, check_v2_signature will fail to open it anyway - if (tries == 10) { - pr_info("%s: timeout for %s\n", __func__, path); - return false; - } - // set debug info to print size and hash to kernel log pr_info("%s: expected size: %u, expected hash: %s\n", path, expected_manager_size, expected_manager_hash); -#ifdef CONFIG_KSU_DEBUG - return check_v2_signature(path, EXPECTED_MANAGER_SIZE, EXPECTED_MANAGER_HASH); -#else return check_v2_signature(path, expected_manager_size, expected_manager_hash); -#endif } diff --git a/drivers/kernelsu/apk_sign.h b/drivers/kernelsu/apk_sign.h index e02aa5144065..bed501c49264 100644 --- a/drivers/kernelsu/apk_sign.h +++ b/drivers/kernelsu/apk_sign.h @@ -3,6 +3,6 @@ #include -bool ksu_is_manager_apk(char *path); +bool is_manager_apk(char *path); #endif diff --git a/drivers/kernelsu/core_hook.c b/drivers/kernelsu/core_hook.c index a9f524c87088..75b22f9a5dfb 100644 --- a/drivers/kernelsu/core_hook.c +++ b/drivers/kernelsu/core_hook.c @@ -51,27 +51,20 @@ #include "kernel_compat.h" #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); -} - +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_TRY_UMOUNT -extern void susfs_run_try_umount_for_current_mnt_ns(void); -#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT +#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; @@ -120,11 +113,27 @@ 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; -extern int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4); +extern int handle_sepolicy(unsigned long arg3, void __user *arg4); bool ksu_su_compat_enabled = true; extern void ksu_sucompat_init(); @@ -132,7 +141,7 @@ extern void ksu_sucompat_exit(); static inline bool is_allow_su() { - if (ksu_is_manager()) { + if (is_manager()) { // we are manager, allow! return true; } @@ -206,11 +215,12 @@ static void disable_seccomp(void) #ifdef CONFIG_SECCOMP current->seccomp.mode = 0; current->seccomp.filter = NULL; + atomic_set(¤t->seccomp.filter_count, 0); #else #endif } -void ksu_escape_to_root(void) +void escape_to_root(void) { struct cred *cred; @@ -268,7 +278,7 @@ void ksu_escape_to_root(void) disable_seccomp(); spin_unlock_irq(¤t->sighand->siglock); - ksu_setup_selinux(profile->selinux_domain); + setup_selinux(profile->selinux_domain); } int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) @@ -305,7 +315,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); - ksu_track_throne(); + track_throne(); return 0; } @@ -330,9 +340,44 @@ static void nuke_ext4_sysfs() { path_put(&path); } +static bool is_system_bin_su(void) +{ + static const char *su_paths[] = { + "/system/bin/su", + "/vendor/bin/su", + "/product/bin/su", + "/system_ext/bin/su", + "/odm/bin/su", + "/system/xbin/su", + "/system_ext/xbin/su" + }; + char path_buf[256]; + char *pathname; + int i; + + struct mm_struct *mm = current->mm; + if (mm && mm->exe_file) { + pathname = d_path(&mm->exe_file->f_path, path_buf, sizeof(path_buf)); + if (!IS_ERR(pathname)) { + for (i = 0; i < ARRAY_SIZE(su_paths); i++) { + if (strcmp(pathname, su_paths[i]) == 0) + return true; + } + } + } + return false; +} + int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { +#ifdef CONFIG_KSU_SUSFS + // - We straight up check if process is supposed to be umounted, return 0 if so + // - This is to prevent side channel attack as much as possible + if (likely(susfs_is_current_proc_umounted())) { + return 0; + } +#endif // if success, we modify the arg5 as result! u32 *result = (u32 *)arg5; u32 reply_ok = KERNEL_SU_OPTION; @@ -350,12 +395,20 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, } bool from_root = 0 == current_uid().val; - bool from_manager = ksu_is_manager(); + bool from_manager = is_manager(); +#ifdef CONFIG_KSU_KPROBES_HOOK + if (!from_root && !from_manager + && !(is_allow_su() && is_system_bin_su())) { + // only root or manager can access this interface + return 0; + } +#else if (!from_root && !from_manager) { // only root or manager can access this interface return 0; } +#endif #ifdef CONFIG_KSU_DEBUG pr_info("option: 0x%x, cmd: %ld\n", option, arg2); @@ -374,7 +427,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); - ksu_escape_to_root(); + escape_to_root(); if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { pr_err("grant_root: prctl reply error\n"); } @@ -399,6 +452,15 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } + if (arg2 == CMD_GET_VERSION_TAG) { + const char *tag = KERNEL_SU_VERSION_TAG; + size_t tag_len = strlen(tag) + 1; + if (copy_to_user((void __user *)arg3, tag, tag_len)) { + pr_err("prctl reply error, cmd: %lu\n", arg2); + } + return 0; + } + if (arg2 == CMD_GET_MANAGER_UID) { uid_t manager_uid = ksu_get_manager_uid(); if (copy_to_user(arg3, &manager_uid, sizeof(manager_uid))) { @@ -429,13 +491,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"); - ksu_on_post_fs_data(); +#ifdef CONFIG_KSU_SUSFS + susfs_on_post_fs_data(); +#endif + on_post_fs_data(); } break; } @@ -444,6 +506,9 @@ 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; } @@ -463,7 +528,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, if (!from_root) { return 0; } - if (!ksu_handle_sepolicy(arg3, arg4)) { + if (!handle_sepolicy(arg3, arg4)) { if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { pr_err("sepolicy: prctl reply error\n"); } @@ -524,6 +589,32 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } +#ifdef CONFIG_KSU_KPROBES_HOOK + if (arg2 == CMD_ENABLE_SU) { + bool enabled = (arg3 != 0); + if (enabled == ksu_su_compat_enabled) { + pr_info("cmd enable su but no need to change.\n"); + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {// return the reply_ok directly + pr_err("prctl reply error, cmd: %lu\n", arg2); + } + return 0; + } + + if (enabled) { + ksu_sucompat_init(); + } else { + ksu_sucompat_exit(); + } + ksu_su_compat_enabled = enabled; + + if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { + pr_err("prctl reply error, cmd: %lu\n", arg2); + } + + return 0; + } +#endif + #ifdef CONFIG_KSU_SUSFS if (current_uid_val == 0) { #ifdef CONFIG_KSU_SUSFS_SUS_PATH @@ -543,6 +634,22 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, pr_info("susfs: copy_to_user() failed\n"); return 0; } + if (arg2 == CMD_SUSFS_ADD_SUS_PATH_LOOP) { + int error = 0; + if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_path))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH_LOOP -> arg3 is not accessible\n"); + return 0; + } + if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { + pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH_LOOP -> arg5 is not accessible\n"); + return 0; + } + error = susfs_add_sus_path_loop((struct st_susfs_sus_path __user*)arg3); + pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH_LOOP -> 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_SET_ANDROID_DATA_ROOT_PATH) { int error = 0; if (!ksu_access_ok((void __user*)arg3, SUSFS_MAX_LEN_PATHNAME)) { @@ -685,11 +792,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, 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) { @@ -867,6 +969,17 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } #endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU + if (arg2 == CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING) { + int error = 0; + if (arg3 != 0 && arg3 != 1) { + pr_err("susfs: CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING -> arg3 can only be 0 or 1\n"); + return 0; + } + susfs_set_avc_log_spoofing(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 @@ -923,7 +1036,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, } return 0; } - +#ifndef CONFIG_KSU_KPROBES_HOOK if (arg2 == CMD_ENABLE_SU) { bool enabled = (arg3 != 0); if (enabled == ksu_su_compat_enabled) { @@ -953,6 +1066,8 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } +#endif + return 0; } @@ -1001,9 +1116,9 @@ static int ksu_umount_mnt(struct path *path, int flags) } #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT -void ksu_try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid) +void try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid) #else -static void ksu_try_umount(const char *mnt, bool check_mnt, int flags) +static void try_umount(const char *mnt, bool check_mnt, int flags) #endif { struct path path; @@ -1040,30 +1155,29 @@ static void ksu_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 */ - ksu_try_umount("/system", true, 0, uid); - ksu_try_umount("/system_ext", true, 0, uid); - ksu_try_umount("/vendor", true, 0, uid); - ksu_try_umount("/product", true, 0, uid); - ksu_try_umount("/odm", true, 0, uid); + try_umount("/odm", true, 0, uid); + try_umount("/system", true, 0, uid); + try_umount("/vendor", true, 0, uid); + try_umount("/product", 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 - ksu_try_umount("/data/adb/modules", false, MNT_DETACH, uid); + try_umount("/data/adb/modules", false, MNT_DETACH, uid); /* For both Legacy KSU and Magic Mount KSU */ - ksu_try_umount("/debug_ramdisk", true, MNT_DETACH, uid); - - // try umount ksu temp path - ksu_try_umount("/sbin", false, MNT_DETACH, uid); + try_umount("/debug_ramdisk", true, MNT_DETACH, uid); + try_umount("/sbin", true, MNT_DETACH, uid); + try_umount("/oem", true, MNT_DETACH, uid); // try umount hosts file - ksu_try_umount("/system/etc/hosts", false, MNT_DETACH, uid); + try_umount("/system/etc/hosts", false, MNT_DETACH, uid); // try umount lsposed dex2oat bins - ksu_try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid); - ksu_try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid); + 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 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! @@ -1083,51 +1197,99 @@ 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_ksu_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 - task_unlock(current); + // 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; + } + + // - 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.val % 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.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); + try_umount("/oem", 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 // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT + + get_task_struct(current); + #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (susfs_is_umount_for_zygote_iso_service_enabled) { - goto out_susfs_try_umount_all; - } + // 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); @@ -1138,20 +1300,7 @@ 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); - 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); - } -#endif // #ifdef CONFIG_KSU_SUSFS -#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT -out_ksu_try_umount: -#endif if (!ksu_uid_should_umount(new_uid.val)) { return 0; } else { @@ -1160,12 +1309,10 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) #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 + bool is_zygote_child = is_zygote(old->security); if (!is_zygote_child) { pr_info("handle umount ignore non zygote child: %d\n", current->pid); @@ -1177,34 +1324,29 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) 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` - ksu_try_umount("/odm", true, 0); - 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("/odm", true, 0); + 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); // try umount ksu temp path - ksu_try_umount("/debug_ramdisk", false, MNT_DETACH); - ksu_try_umount("/sbin", false, MNT_DETACH); + try_umount("/debug_ramdisk", false, MNT_DETACH); + try_umount("/sbin", false, MNT_DETACH); // try umount hosts file - ksu_try_umount("/system/etc/hosts", false, MNT_DETACH); + try_umount("/system/etc/hosts", false, MNT_DETACH); // try umount lsposed dex2oat bins - ksu_try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH); - ksu_try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH); -#endif + try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH); + try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH); return 0; } +#endif // #ifdef CONFIG_KSU_SUSFS // Init functons diff --git a/drivers/kernelsu/kernel_compat.h b/drivers/kernelsu/kernel_compat.h index cad307a00513..e7f8dfed858b 100644 --- a/drivers/kernelsu/kernel_compat.h +++ b/drivers/kernelsu/kernel_compat.h @@ -5,6 +5,30 @@ #include #include "ss/policydb.h" #include "linux/key.h" +#include + +/** + * list_count_nodes - count the number of nodes in a list + * the head of the list + * + * Returns the number of nodes in the list + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) +static inline size_t list_count_nodes(const struct list_head *head) +{ + const struct list_head *pos; + size_t count = 0; + + if (!head) + return 0; + + list_for_each(pos, head) { + count++; + } + + return count; +} +#endif /* * Adapt to Huawei HISI kernel without affecting other kernels , diff --git a/drivers/kernelsu/ksu.c b/drivers/kernelsu/ksu.c index a8a02c2f68cf..7d9db0a61918 100644 --- a/drivers/kernelsu/ksu.c +++ b/drivers/kernelsu/ksu.c @@ -41,7 +41,7 @@ extern void ksu_sucompat_exit(); extern void ksu_ksud_init(); extern void ksu_ksud_exit(); -int __init ksu_kernelsu_init(void) +int __init kernelsu_init(void) { #ifdef CONFIG_KSU_DEBUG pr_alert("*************************************************************"); @@ -80,7 +80,7 @@ int __init ksu_kernelsu_init(void) return 0; } -void ksu_kernelsu_exit(void) +void kernelsu_exit(void) { ksu_allowlist_exit(); @@ -96,8 +96,8 @@ void ksu_kernelsu_exit(void) ksu_core_exit(); } -module_init(ksu_kernelsu_init); -module_exit(ksu_kernelsu_exit); +module_init(kernelsu_init); +module_exit(kernelsu_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("weishu"); diff --git a/drivers/kernelsu/ksu.h b/drivers/kernelsu/ksu.h index 5101c695ea62..88823d8b18b6 100644 --- a/drivers/kernelsu/ksu.h +++ b/drivers/kernelsu/ksu.h @@ -5,6 +5,7 @@ #include #define KERNEL_SU_VERSION KSU_VERSION +#define KERNEL_SU_VERSION_TAG KSU_VERSION_TAG #define KERNEL_SU_OPTION 0xDEADBEEF #define CMD_GRANT_ROOT 0 @@ -26,6 +27,7 @@ #define CMD_GET_MANAGER_UID 16 #define CMD_HOOK_MODE 0xC0DEAD1A +#define CMD_GET_VERSION_TAG 0xC0DEAD1B #define EVENT_POST_FS_DATA 1 #define EVENT_BOOT_COMPLETED 2 diff --git a/drivers/kernelsu/ksud.c b/drivers/kernelsu/ksud.c index b8c4f1fb88a8..5d05fafd7495 100644 --- a/drivers/kernelsu/ksud.c +++ b/drivers/kernelsu/ksud.c @@ -74,15 +74,15 @@ u32 ksu_devpts_sid; bool ksu_is_compat __read_mostly = false; #endif -void ksu_on_post_fs_data(void) +void on_post_fs_data(void) { static bool done = false; if (done) { - pr_info("ksu_on_post_fs_data already done\n"); + pr_info("on_post_fs_data already done\n"); return; } done = true; - pr_info("ksu_on_post_fs_data!\n"); + pr_info("on_post_fs_data!\n"); ksu_load_allow_list(); // sanity check, this may influence the performance stop_input_hook(); @@ -206,7 +206,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"); - ksu_apply_kernelsu_rules(); + apply_kernelsu_rules(); init_second_stage_executed = true; ksu_android_ns_fs_check(); } @@ -230,7 +230,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"); - ksu_apply_kernelsu_rules(); + apply_kernelsu_rules(); init_second_stage_executed = true; ksu_android_ns_fs_check(); } @@ -267,7 +267,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"); - ksu_apply_kernelsu_rules(); + apply_kernelsu_rules(); init_second_stage_executed = true; ksu_android_ns_fs_check(); @@ -282,7 +282,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); - ksu_on_post_fs_data(); // we keep this for old ksud + on_post_fs_data(); // we keep this for old ksud stop_execve_hook(); } diff --git a/drivers/kernelsu/ksud.h b/drivers/kernelsu/ksud.h index 26974c9c4fe5..cc2df243a8f0 100644 --- a/drivers/kernelsu/ksud.h +++ b/drivers/kernelsu/ksud.h @@ -5,7 +5,7 @@ #define KSUD_PATH "/data/adb/ksud" -void ksu_on_post_fs_data(void); +void on_post_fs_data(void); bool ksu_is_safe_mode(void); diff --git a/drivers/kernelsu/manager.h b/drivers/kernelsu/manager.h index 93fa26786a3a..be5bbced6f73 100644 --- a/drivers/kernelsu/manager.h +++ b/drivers/kernelsu/manager.h @@ -13,7 +13,7 @@ static inline bool ksu_is_manager_uid_valid() return ksu_manager_uid != KSU_INVALID_UID; } -static inline bool ksu_is_manager() +static inline bool is_manager() { return unlikely(ksu_manager_uid == current_uid().val); } diff --git a/drivers/kernelsu/selinux/rules.c b/drivers/kernelsu/selinux/rules.c index 5d8326867a29..d5dee0790810 100644 --- a/drivers/kernelsu/selinux/rules.c +++ b/drivers/kernelsu/selinux/rules.c @@ -24,10 +24,10 @@ static struct policydb *get_policydb(void) // selinux_state does not exists before 4.19 #ifdef KSU_COMPAT_USE_SELINUX_STATE #ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS - struct selinux_policy *policy = rcu_dereference(selinux_state.policy); + struct selinux_policy *policy = selinux_state.policy; db = &policy->policydb; #else - struct selinux_ss *ss = rcu_dereference(selinux_state.ss); + struct selinux_ss *ss = selinux_state.ss; db = &ss->policydb; #endif #else @@ -38,11 +38,11 @@ static struct policydb *get_policydb(void) static DEFINE_MUTEX(ksu_rules); -void ksu_apply_kernelsu_rules() +void apply_kernelsu_rules() { struct policydb *db; - if (!ksu_getenforce()) { + if (!getenforce()) { pr_info("SELinux permissive or disabled, apply rules!\n"); } @@ -142,6 +142,7 @@ void ksu_apply_kernelsu_rules() #ifdef CONFIG_KSU_SUSFS // Allow umount in zygote process without installing zygisk ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount"); + susfs_set_kernel_sid(); susfs_set_init_sid(); susfs_set_ksu_sid(); susfs_set_zygote_sid(); @@ -236,13 +237,15 @@ static void reset_avc_cache() selinux_xfrm_notify_policyload(); } -int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4) +int handle_sepolicy(unsigned long arg3, void __user *arg4) { + struct policydb *db; + if (!arg4) { return -1; } - if (!ksu_getenforce()) { + if (!getenforce()) { pr_info("SELinux permissive or disabled when handle policy!\n"); } @@ -299,9 +302,9 @@ int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4) subcmd = data.subcmd; #endif - rcu_read_lock(); + mutex_lock(&ksu_rules); - struct policydb *db = get_policydb(); + db = get_policydb(); int ret = -1; if (cmd == CMD_NORMAL_PERM) { @@ -551,7 +554,7 @@ int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4) } exit: - rcu_read_unlock(); + mutex_unlock(&ksu_rules); // only allow and xallow needs to reset avc cache, but we cannot do that because // we are in atomic context. so we just reset it every time. diff --git a/drivers/kernelsu/selinux/selinux.c b/drivers/kernelsu/selinux/selinux.c index e171e0109d29..1726aa6164a1 100644 --- a/drivers/kernelsu/selinux/selinux.c +++ b/drivers/kernelsu/selinux/selinux.c @@ -11,9 +11,11 @@ #ifdef CONFIG_KSU_SUSFS #define KERNEL_INIT_DOMAIN "u:r:init:s0" #define KERNEL_ZYGOTE_DOMAIN "u:r:zygote:s0" +#define KERNEL_KERNEL_DOMAIN "u:r:kernel:s0" u32 susfs_ksu_sid = 0; u32 susfs_init_sid = 0; u32 susfs_zygote_sid = 0; +u32 susfs_kernel_sid = 0; #endif static int transive_to_domain(const char *domain) @@ -45,7 +47,7 @@ static int transive_to_domain(const char *domain) return error; } -void ksu_setup_selinux(const char *domain) +void setup_selinux(const char *domain) { if (transive_to_domain(domain)) { pr_err("transive domain failed.\n"); @@ -60,7 +62,7 @@ if (!is_domain_permissive) { }*/ } -void ksu_setenforce(bool enforce) +void setenforce(bool enforce) { #ifdef CONFIG_SECURITY_SELINUX_DEVELOP #ifdef KSU_COMPAT_USE_SELINUX_STATE @@ -71,7 +73,7 @@ void ksu_setenforce(bool enforce) #endif } -bool ksu_getenforce() +bool getenforce() { #ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef KSU_COMPAT_USE_SELINUX_STATE @@ -107,7 +109,7 @@ static inline u32 current_sid(void) } #endif -bool ksu_is_ksu_domain() +bool is_ksu_domain() { char *domain; u32 seclen; @@ -121,7 +123,7 @@ bool ksu_is_ksu_domain() return result; } -bool ksu_is_zygote(void *sec) +bool is_zygote(void *sec) { struct task_security_struct *tsec = (struct task_security_struct *)sec; if (!tsec) { @@ -214,6 +216,11 @@ void susfs_set_init_sid(void) bool susfs_is_current_init_domain(void) { return unlikely(current_sid() == susfs_init_sid); } + +void susfs_set_kernel_sid(void) +{ + susfs_set_sid(KERNEL_KERNEL_DOMAIN, &susfs_kernel_sid); +} #endif #define DEVPTS_DOMAIN "u:object_r:ksu_file:s0" diff --git a/drivers/kernelsu/selinux/selinux.h b/drivers/kernelsu/selinux/selinux.h index d0dfdf9c935b..91894c8c8183 100644 --- a/drivers/kernelsu/selinux/selinux.h +++ b/drivers/kernelsu/selinux/selinux.h @@ -8,17 +8,17 @@ #define KSU_COMPAT_USE_SELINUX_STATE #endif -void ksu_setup_selinux(const char *); +void setup_selinux(const char *); -void ksu_setenforce(bool); +void setenforce(bool); -bool ksu_getenforce(); +bool getenforce(); -bool ksu_is_ksu_domain(); +bool is_ksu_domain(); -bool ksu_is_zygote(void *cred); +bool is_zygote(void *cred); -void ksu_apply_kernelsu_rules(); +void apply_kernelsu_rules(); #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT bool susfs_is_sid_equal(void *sec, u32 sid2); diff --git a/drivers/kernelsu/setup.sh b/drivers/kernelsu/setup.sh index cac376d5dc22..aadc1adb0396 100755 --- a/drivers/kernelsu/setup.sh +++ b/drivers/kernelsu/setup.sh @@ -43,7 +43,7 @@ setup_kernelsu() { cd "$GKI_ROOT/KernelSU-Next" git stash && echo "[-] Stashed current changes." if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then - git checkout next-susfs-a13-5.15-dev && echo "[-] Switched to next-susfs-a13-5.15-dev branch." + git checkout next && echo "[-] Switched to next branch." fi git pull && echo "[+] Repository updated." if [ -z "${1-}" ]; then diff --git a/drivers/kernelsu/sucompat.c b/drivers/kernelsu/sucompat.c index 3140f00fc57d..a8045706f9cf 100644 --- a/drivers/kernelsu/sucompat.c +++ b/drivers/kernelsu/sucompat.c @@ -31,7 +31,7 @@ static bool ksu_sucompat_non_kp __read_mostly = true; #endif -extern void ksu_escape_to_root(); +extern void escape_to_root(); static const char sh_path[] = "/system/bin/sh"; static const char ksud_path[] = KSUD_PATH; @@ -66,13 +66,13 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, #endif #ifndef CONFIG_KSU_SUSFS_SUS_SU - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } + if (!ksu_is_allow_uid(current_uid().val)) { + return 0; + } #endif #ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su)] = {0}; + char path[sizeof(su) + 1] = {0}; #else char path[sizeof(su) + 1]; memset(path, 0, sizeof(path)); @@ -125,7 +125,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) } #ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su)] = {0}; + char path[sizeof(su) + 1] = {0}; #else char path[sizeof(su) + 1]; memset(path, 0, sizeof(path)); @@ -187,7 +187,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, pr_info("do_execveat_common su found\n"); memcpy((void *)filename->name, ksud_path, sizeof(ksud_path)); - ksu_escape_to_root(); + escape_to_root(); return 0; } @@ -197,7 +197,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, int *__never_use_flags) { #ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su)] = {0}; + char path[sizeof(su) + 1] = {0}; #else char path[sizeof(su) + 1]; #endif @@ -211,7 +211,9 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, if (unlikely(!filename_user)) return 0; +#ifndef CONFIG_KSU_SUSFS_SUS_SU memset(path, 0, sizeof(path)); +#endif ksu_strncpy_from_user_retry(path, *filename_user, sizeof(path)); if (likely(memcmp(path, su, sizeof(su)))) @@ -223,7 +225,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(); - ksu_escape_to_root(); + escape_to_root(); return 0; } @@ -361,7 +363,8 @@ void ksu_sucompat_init() void ksu_sucompat_exit() { #ifdef CONFIG_KSU_KPROBES_HOOK - for (int i = 0; i < ARRAY_SIZE(su_kps); i++) { + int i; + for (i = 0; i < ARRAY_SIZE(su_kps); i++) { destroy_kprobe(&su_kps[i]); } #else diff --git a/drivers/kernelsu/throne_tracker.c b/drivers/kernelsu/throne_tracker.c index bfd337170b02..3e80dcdeeaab 100644 --- a/drivers/kernelsu/throne_tracker.c +++ b/drivers/kernelsu/throne_tracker.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "allowlist.h" #include "klog.h" // IWYU pragma: keep @@ -14,8 +17,24 @@ #include "kernel_compat.h" uid_t ksu_manager_uid = KSU_INVALID_UID; +static uid_t locked_manager_uid = KSU_INVALID_UID; + +static atomic_t pkg_lock = ATOMIC_INIT(0); +static atomic_t scan_lock = ATOMIC_INIT(0); #define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list.tmp" +#define USER_DATA_PATH "/data/user_de/0" +#define USER_DATA_PATH_LEN 288 + +struct uid_scan_stats { + size_t errors_encountered; +}; + +struct user_data_context { + struct dir_context ctx; + struct list_head *uid_list; + struct uid_scan_stats *stats; +}; struct uid_data { struct list_head list; @@ -75,18 +94,23 @@ static void crown_manager(const char *apk, struct list_head *uid_data) #ifdef KSU_MANAGER_PACKAGE // pkg is `/` if (strncmp(pkg, KSU_MANAGER_PACKAGE, sizeof(KSU_MANAGER_PACKAGE))) { - pr_info("manager package is inconsistent with kernel build: %s\n", + pr_info("manager package inconsistent: %s\n", KSU_MANAGER_PACKAGE); return; } #endif - struct list_head *list = (struct list_head *)uid_data; struct uid_data *np; - - list_for_each_entry (np, list, list) { + list_for_each_entry(np, uid_data, list) { if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) { - pr_info("Crowning manager: %s(uid=%d)\n", pkg, np->uid); - ksu_set_manager_uid(np->uid); + // unlock previously locked UID if different + if (locked_manager_uid != KSU_INVALID_UID && locked_manager_uid != np->uid) { + pr_info("Unlocking previous manager UID: %d\n", locked_manager_uid); + ksu_invalidate_manager_uid(); // unlock old one + locked_manager_uid = KSU_INVALID_UID; + } + pr_info("Crowning new manager: %s (uid=%d)\n", pkg, np->uid); + ksu_set_manager_uid(np->uid); // throne new UID + locked_manager_uid = np->uid; // store locked UID break; } } @@ -128,6 +152,154 @@ struct my_dir_context { #define FILLDIR_ACTOR_STOP -EINVAL #endif +FILLDIR_RETURN_TYPE user_data_actor(struct dir_context *ctx, const char *name, + int namelen, loff_t off, u64 ino, + unsigned int d_type) +{ + struct user_data_context *my_ctx = + container_of(ctx, struct user_data_context, ctx); + + if (!my_ctx || !my_ctx->uid_list) + return FILLDIR_ACTOR_STOP; + + if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen)) + return FILLDIR_ACTOR_CONTINUE; + + if (d_type != DT_DIR) + return FILLDIR_ACTOR_CONTINUE; + + if (namelen >= KSU_MAX_PACKAGE_NAME) { + pr_warn("Package name too long: %.*s\n", namelen, name); + if (my_ctx->stats) + my_ctx->stats->errors_encountered++; + return FILLDIR_ACTOR_CONTINUE; + } + + char package_path[USER_DATA_PATH_LEN]; + if (snprintf(package_path, sizeof(package_path), "%s/%.*s", + USER_DATA_PATH, namelen, name) >= sizeof(package_path)) { + pr_err("Path too long for package: %.*s\n", namelen, name); + if (my_ctx->stats) + my_ctx->stats->errors_encountered++; + return FILLDIR_ACTOR_CONTINUE; + } + + struct path path; + int err = kern_path(package_path, LOOKUP_FOLLOW, &path); + if (err) { + pr_debug("Package path lookup failed: %s (err: %d)\n", package_path, err); + if (my_ctx->stats) + my_ctx->stats->errors_encountered++; + return FILLDIR_ACTOR_CONTINUE; + } + + struct kstat stat; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || defined(KSU_HAS_NEW_VFS_GETATTR) + err = vfs_getattr(&path, &stat, STATX_UID, AT_STATX_SYNC_AS_STAT); +#else + err = vfs_getattr(&path, &stat); +#endif + path_put(&path); + + if (err) { + pr_debug("Failed to get attributes for: %s (err: %d)\n", package_path, err); + if (my_ctx->stats) + my_ctx->stats->errors_encountered++; + return FILLDIR_ACTOR_CONTINUE; + } + + uid_t uid = from_kuid(&init_user_ns, stat.uid); + if (uid == (uid_t)-1) { + pr_warn("Invalid UID for package: %.*s\n", namelen, name); + if (my_ctx->stats) + my_ctx->stats->errors_encountered++; + return FILLDIR_ACTOR_CONTINUE; + } + + struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC); + if (!data) { + pr_err("Failed to allocate memory for package: %.*s\n", namelen, name); + if (my_ctx->stats) + my_ctx->stats->errors_encountered++; + return FILLDIR_ACTOR_CONTINUE; + } + + data->uid = uid; + size_t copy_len = min(namelen, KSU_MAX_PACKAGE_NAME - 1); + strncpy(data->package, name, copy_len); + data->package[copy_len] = '\0'; + + list_add_tail(&data->list, my_ctx->uid_list); + + return FILLDIR_ACTOR_CONTINUE; +} + +/* + * small helper to check if lock is held + * false - file is stable + * true - file is being deleted/renamed + * possibly optional + * + */ +bool is_lock_held(const char *path) +{ + struct path kpath; + + // kern_path returns 0 on success + if (kern_path(path, 0, &kpath)) + return true; + + // just being defensive + if (!kpath.dentry) { + path_put(&kpath); + return true; + } + + if (!spin_trylock(&kpath.dentry->d_lock)) { + pr_info("%s: lock held, bail out!\n", __func__); + path_put(&kpath); + return true; + } + // we hold it ourselves here! + + spin_unlock(&kpath.dentry->d_lock); + path_put(&kpath); + return false; +} + +static int scan_user_data_for_uids(struct list_head *uid_list) +{ + struct file *dir_file; + struct uid_scan_stats stats = {0}; + int ret = 0; + + if (!uid_list) { + return -EINVAL; + } + + dir_file = ksu_filp_open_compat(USER_DATA_PATH, O_RDONLY, 0); + if (IS_ERR(dir_file)) { + pr_err("Failed to open %s, err: (%ld)\n", USER_DATA_PATH, PTR_ERR(dir_file)); + return PTR_ERR(dir_file); + } + + struct user_data_context ctx = { + .ctx.actor = user_data_actor, + .uid_list = uid_list, + .stats = &stats + }; + + ret = iterate_dir(dir_file, &ctx.ctx); + filp_close(dir_file, NULL); + + // if 0 errors, that means everything were fine. + if (stats.errors_encountered > 0) { + pr_info("Got %zu error(s) while scanning %s directory.\n", + stats.errors_encountered, USER_DATA_PATH); + } + return ret; +} + FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, int namelen, loff_t off, u64 ino, unsigned int d_type) @@ -192,7 +364,7 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, } } - bool is_manager = ksu_is_manager_apk(dirpath); + bool is_manager = is_manager_apk(dirpath); pr_info("Found new base.apk at path: %s, is_manager: %d\n", dirpath, is_manager); if (is_manager) { @@ -216,39 +388,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, return FILLDIR_ACTOR_CONTINUE; } -/* - * small helper to check if lock is held - * false - file is stable - * true - file is being deleted/renamed - * possibly optional - * - */ -bool is_lock_held(const char *path) -{ - struct path kpath; - - // kern_path returns 0 on success - if (kern_path(path, 0, &kpath)) - return true; - - // just being defensive - if (!kpath.dentry) { - path_put(&kpath); - return true; - } - - if (!spin_trylock(&kpath.dentry->d_lock)) { - pr_info("%s: lock held, bail out!\n", __func__); - path_put(&kpath); - return true; - } - // we hold it ourselves here! - - spin_unlock(&kpath.dentry->d_lock); - path_put(&kpath); - return false; -} - // compat: https://elixir.bootlin.com/linux/v3.9/source/include/linux/fs.h#L771 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) #define S_MAGIC_COMPAT(x) ((x)->f_inode->i_sb->s_magic) @@ -256,7 +395,7 @@ bool is_lock_held(const char *path) #define S_MAGIC_COMPAT(x) ((x)->f_path.dentry->d_inode->i_sb->s_magic) #endif -void search_manager(const char *path, int depth, struct list_head *uid_data) +static void search_manager(const char *path, int depth, struct list_head *uid_data) { int i, stop = 0; struct list_head data_path_list; @@ -297,7 +436,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file)); goto skip_iterate; } - + // grab magic on first folder, which is /data/app if (!data_app_magic) { if (S_MAGIC_COMPAT(file)) { @@ -351,108 +490,117 @@ static bool is_uid_exist(uid_t uid, char *package, void *data) return exist; } -void ksu_track_throne() +void track_throne() { + struct list_head uid_list; + struct uid_data *np, *n; struct file *fp; - int tries = 0; + int ret = 0; + INIT_LIST_HEAD(&uid_list); - while (tries++ < 10) { - if (!is_lock_held(SYSTEM_PACKAGES_LIST_PATH)) { - fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); - if (!IS_ERR(fp)) - break; + pr_info("Scanning %s directory..\n", USER_DATA_PATH); + ret = scan_user_data_for_uids(&uid_list); + + if (ret < 0) { + pr_warn("Failed to scan %s, falling back to %s\n", + USER_DATA_PATH, SYSTEM_PACKAGES_LIST_PATH); + + fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", + __func__, PTR_ERR(fp)); + return; } - - pr_info("%s: waiting for %s\n", __func__, SYSTEM_PACKAGES_LIST_PATH); - msleep(100); // migth as well add a delay - }; - - if (IS_ERR(fp)) { - pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp)); - return; - } else - pr_info("%s: %s found!\n", __func__, SYSTEM_PACKAGES_LIST_PATH); - struct list_head uid_list; - INIT_LIST_HEAD(&uid_list); + if (atomic_read(&pkg_lock) != 1) { + pr_info("%s: locking to only read %s\n", __func__, SYSTEM_PACKAGES_LIST_PATH); + atomic_set(&pkg_lock, 1); + } - char chr = 0; - loff_t pos = 0; - loff_t line_start = 0; - char buf[KSU_MAX_PACKAGE_NAME]; - for (;;) { - ssize_t count = - ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); - if (count != sizeof(chr)) - break; - if (chr != '\n') - continue; + char chr = 0; + loff_t pos = 0; + loff_t line_start = 0; + char buf[KSU_MAX_PACKAGE_NAME]; + for (;;) { + ssize_t count = ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); + if (count != sizeof(chr)) + break; + if (chr != '\n') + continue; - count = ksu_kernel_read_compat(fp, buf, sizeof(buf), - &line_start); + count = ksu_kernel_read_compat(fp, buf, sizeof(buf), &line_start); - struct uid_data *data = - kzalloc(sizeof(struct uid_data), GFP_ATOMIC); - if (!data) { - filp_close(fp, 0); - goto out; - } + struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC); + if (!data) { + filp_close(fp, 0); + goto out; + } - char *tmp = buf; - const char *delim = " "; - char *package = strsep(&tmp, delim); - char *uid = strsep(&tmp, delim); - if (!uid || !package) { - pr_err("update_uid: package or uid is NULL!\n"); - break; + char *tmp = buf; + const char *delim = " "; + char *package = strsep(&tmp, delim); + char *uid_str = strsep(&tmp, delim); + if (!uid_str || !package) { + pr_err("update_uid: package or uid is NULL!\n"); + kfree(data); + break; + } + + u32 res; + if (kstrtou32(uid_str, 10, &res)) { + pr_err("update_uid: uid parse err\n"); + kfree(data); + break; + } + + data->uid = res; + strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); + list_add_tail(&data->list, &uid_list); + + // reset line start + line_start = pos; } + filp_close(fp, 0); + } else { + pr_info("Scanned %zu package(s) from user data directory.\n", + list_count_nodes(&uid_list)); - u32 res; - if (kstrtou32(uid, 10, &res)) { - pr_err("update_uid: uid parse err\n"); - break; + if (atomic_read(&scan_lock) != 1) { + pr_info("%s: locking to only read %s directory.\n", + __func__, USER_DATA_PATH); + atomic_set(&scan_lock, 1); } - data->uid = res; - strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); - list_add_tail(&data->list, &uid_list); - // reset line start - line_start = pos; } - filp_close(fp, 0); - // now update uid list - struct uid_data *np; - struct uid_data *n; - - // first, check if manager_uid exist! - bool manager_exist = false; - list_for_each_entry (np, &uid_list, list) { - // if manager is installed in work profile, the uid in packages.list is still equals main profile - // don't delete it in this case! - int manager_uid = ksu_get_manager_uid() % 100000; - if (np->uid == manager_uid) { + // check if manager UID exists + bool manager_exist = false; + int current_manager_uid = ksu_get_manager_uid() % 100000; + + list_for_each_entry(np, &uid_list, list) { + if (np->uid == current_manager_uid) { manager_exist = true; break; } } + if (!manager_exist && locked_manager_uid != KSU_INVALID_UID) { + pr_info("Manager APK removed, unlocking previous UID: %d\n", locked_manager_uid); + ksu_invalidate_manager_uid(); + locked_manager_uid = KSU_INVALID_UID; + } + if (!manager_exist) { - if (ksu_is_manager_uid_valid()) { - pr_info("manager is uninstalled, invalidate it!\n"); - ksu_invalidate_manager_uid(); - goto prune; - } - pr_info("Searching manager...\n"); + pr_info("Searching for manager...\n"); search_manager("/data/app", 2, &uid_list); - pr_info("Search manager finished\n"); + pr_info("Manager search finished\n"); } -prune: - // then prune the allowlist + // prune the allowlist ksu_prune_allowlist(is_uid_exist, &uid_list); + out: // free uid_list - list_for_each_entry_safe (np, n, &uid_list, list) { + list_for_each_entry_safe(np, n, &uid_list, list) { list_del(&np->list); kfree(np); } diff --git a/drivers/kernelsu/throne_tracker.h b/drivers/kernelsu/throne_tracker.h index 98bb9d5916f7..5d7f477003ac 100644 --- a/drivers/kernelsu/throne_tracker.h +++ b/drivers/kernelsu/throne_tracker.h @@ -5,8 +5,6 @@ void ksu_throne_tracker_init(); void ksu_throne_tracker_exit(); -void ksu_track_throne(); - -bool is_lock_held(const char *path); +void track_throne(); #endif diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 84377423aa8f..b95d92858c71 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -124,6 +124,4 @@ source "drivers/staging/axis-fifo/Kconfig" source "drivers/staging/qcacld-3.0/Kconfig" -source "drivers/staging/kernelsu/Kconfig" - endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 80385eb5ab1f..6c626c8afb31 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -52,4 +52,3 @@ obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ obj-$(CONFIG_QCA_CLD_WLAN) += qcacld-3.0/ -obj-$(CONFIG_KSU) += kernelsu/ diff --git a/drivers/staging/kernelsu/Kconfig b/drivers/staging/kernelsu/Kconfig deleted file mode 100644 index 14d3e854547f..000000000000 --- a/drivers/staging/kernelsu/Kconfig +++ /dev/null @@ -1,178 +0,0 @@ -menu "KernelSU" - -config KSU - tristate "KernelSU function support" - depends on OVERLAY_FS - default y - help - Enable kernel-level root privileges on Android System. - To compile as a module, choose M here: the - module will be called kernelsu. - -config KSU_KPROBES_HOOK - bool "Use kprobes for kernelsu" - depends on KSU - depends on KPROBES - default y - help - Disable if you use manual hooks. - -config KSU_DEBUG - bool "KernelSU debug mode" - depends on KSU - default n - help - Enable KernelSU debug mode. - -config KSU_ALLOWLIST_WORKAROUND - bool "KernelSU Session Keyring Init workaround" - depends on KSU - default n - help - Enable session keyring init workaround for problematic devices. - Useful for situations where the SU allowlist is not kept after a reboot. - -config KSU_LSM_SECURITY_HOOKS - bool "use lsm security hooks" - depends on KSU - default y - help - Disabling this is mostly only useful for kernel 4.1 and older. - Make sure to implement manual hooks on security/security.c. - -menu "KernelSU - SUSFS" -config KSU_SUSFS - bool "KernelSU addon - SUSFS" - depends on KSU - depends on THREAD_INFO_IN_TASK - 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 y)" - 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. - - Includes temp fix for the leaks of app path in /sdcard/Android/data directory. - - 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_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 && KSU_KPROBES_HOOK - 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/drivers/staging/kernelsu/LICENSE b/drivers/staging/kernelsu/LICENSE deleted file mode 100644 index d159169d1050..000000000000 --- a/drivers/staging/kernelsu/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/drivers/staging/kernelsu/Makefile b/drivers/staging/kernelsu/Makefile deleted file mode 100644 index 6c1c7bb2bfe6..000000000000 --- a/drivers/staging/kernelsu/Makefile +++ /dev/null @@ -1,187 +0,0 @@ -kernelsu-objs := ksu.o -kernelsu-objs += allowlist.o -kernelsu-objs += apk_sign.o -kernelsu-objs += sucompat.o -kernelsu-objs += throne_tracker.o -kernelsu-objs += core_hook.o -kernelsu-objs += ksud.o -kernelsu-objs += embed_ksud.o -kernelsu-objs += kernel_compat.o - -kernelsu-objs += selinux/selinux.o -kernelsu-objs += selinux/sepolicy.o -kernelsu-objs += selinux/rules.o -ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include -ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h - -obj-$(CONFIG_KSU) += kernelsu.o - -$(eval KSU_VERSION=12803) -$(info -- KernelSU-Next version: $(KSU_VERSION)) -ccflags-y += -DKSU_VERSION=$(KSU_VERSION) - -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 - -ifeq ($(shell grep -q "strncpy_from_user_nofault" $(srctree)/include/linux/uaccess.h; echo $$?),0) -ccflags-y += -DKSU_STRNCPY_FROM_USER_NOFAULT -endif - -ifeq ($(shell grep -q "ssize_t kernel_read" $(srctree)/fs/read_write.c; echo $$?),0) -ccflags-y += -DKSU_KERNEL_READ -endif - -ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "const void" ; echo $$?),0) -ccflags-y += -DKSU_KERNEL_WRITE -endif - -ifndef KSU_NEXT_MANAGER_SIZE -KSU_NEXT_MANAGER_SIZE := 0x3e6 -endif - -ifndef KSU_NEXT_MANAGER_HASH -KSU_NEXT_MANAGER_HASH := 79e590113c4c4c0c222978e413a5faa801666957b1212a328e46c00c69821bf7 -endif - -ifdef KSU_MANAGER_PACKAGE -ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\" -$(info -- KernelSU-Next Manager package name: $(KSU_MANAGER_PACKAGE)) -endif - -$(info -- KernelSU-Next Manager signature size: $(KSU_NEXT_MANAGER_SIZE)) -$(info -- KernelSU-Next Manager signature hash: $(KSU_NEXT_MANAGER_HASH)) - -ccflags-y += -DEXPECTED_MANAGER_SIZE=$(KSU_NEXT_MANAGER_SIZE) -ccflags-y += -DEXPECTED_MANAGER_HASH=\"$(KSU_NEXT_MANAGER_HASH)\" - -ccflags-y += -DKSU_UMOUNT - -ifneq ($(shell grep -Eq "^static int can_umount" $(srctree)/fs/namespace.c; echo $$?),0) -$(info -- KSU_NEXT: 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_NEXT: 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_NEXT: adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h) -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 "get_cred_rcu" $(srctree)/include/linux/cred.h; echo $$?),0) -$(info -- KSU_SUSFS: adding function 'static inline const struct cred *get_cred_rcu();' to $(srctree)/include/linux/cred.h) -GET_CRED_RCU = static inline const struct cred *get_cred_rcu(const struct cred *cred)\n\ -{\n\t\ - struct cred *nonconst_cred = (struct cred *) cred;\n\t\ - if (!cred)\n\t\t\ - return NULL;\n\t\ - if (!atomic_inc_not_zero(&nonconst_cred->usage))\n\t\t\ - return NULL;\n\t\ - validate_creds(cred);\n\t\ - return cred;\n\ -}\n -$(shell sed -i '/^static inline void put_cred/i $(GET_CRED_RCU)' $(srctree)/include/linux/cred.h;) -endif - -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/drivers/staging/kernelsu/allowlist.c b/drivers/staging/kernelsu/allowlist.c deleted file mode 100644 index 6f2557c9704e..000000000000 --- a/drivers/staging/kernelsu/allowlist.c +++ /dev/null @@ -1,528 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) -#include -#endif - -#include "ksu.h" -#include "klog.h" // IWYU pragma: keep -#include "selinux/selinux.h" -#include "kernel_compat.h" -#include "allowlist.h" -#include "manager.h" - -#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32 -#define FILE_FORMAT_VERSION 3 // u32 - -#define KSU_APP_PROFILE_PRESERVE_UID 9999 // NOBODY_UID -#define KSU_DEFAULT_SELINUX_DOMAIN "u:r:su:s0" - -static DEFINE_MUTEX(allowlist_mutex); - -// default profiles, these may be used frequently, so we cache it -static struct root_profile default_root_profile; -static struct non_root_profile default_non_root_profile; - -static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly __aligned(PAGE_SIZE); -static int allow_list_pointer __read_mostly = 0; - -static void remove_uid_from_arr(uid_t uid) -{ - int *temp_arr; - int i, j; - - if (allow_list_pointer == 0) - return; - - temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL); - if (temp_arr == NULL) { - pr_err("%s: unable to allocate memory\n", __func__); - return; - } - - for (i = j = 0; i < allow_list_pointer; i++) { - if (allow_list_arr[i] == uid) - continue; - temp_arr[j++] = allow_list_arr[i]; - } - - allow_list_pointer = j; - - for (; j < ARRAY_SIZE(allow_list_arr); j++) - temp_arr[j] = -1; - - memcpy(&allow_list_arr, temp_arr, PAGE_SIZE); - kfree(temp_arr); -} - -static void init_default_profiles() -{ - kernel_cap_t full_cap = CAP_FULL_SET; - - default_root_profile.uid = 0; - default_root_profile.gid = 0; - default_root_profile.groups_count = 1; - default_root_profile.groups[0] = 0; - memcpy(&default_root_profile.capabilities.effective, &full_cap, - sizeof(default_root_profile.capabilities.effective)); - default_root_profile.namespaces = 0; - strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); - - // This means that we will umount modules by default! - default_non_root_profile.umount_modules = true; -} - -struct perm_data { - struct list_head list; - struct app_profile profile; -}; - -static struct list_head allow_list; - -static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE); -#define BITMAP_UID_MAX ((sizeof(allow_list_bitmap) * BITS_PER_BYTE) - 1) - -#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist" - -static struct work_struct ksu_save_work; -static struct work_struct ksu_load_work; - -static bool persistent_allow_list(void); - -void ksu_show_allow_list(void) -{ - struct perm_data *p = NULL; - struct list_head *pos = NULL; - pr_info("ksu_show_allow_list\n"); - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - pr_info("uid :%d, allow: %d\n", p->profile.current_uid, - p->profile.allow_su); - } -} - -#ifdef CONFIG_KSU_DEBUG -static void ksu_grant_root_to_shell() -{ - struct app_profile profile = { - .version = KSU_APP_PROFILE_VER, - .allow_su = true, - .current_uid = 2000, - }; - strcpy(profile.key, "com.android.shell"); - strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN); - ksu_set_app_profile(&profile, false); -} -#endif - -bool ksu_get_app_profile(struct app_profile *profile) -{ - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool found = false; - - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - bool uid_match = profile->current_uid == p->profile.current_uid; - if (uid_match) { - // found it, override it with ours - memcpy(profile, &p->profile, sizeof(*profile)); - found = true; - goto exit; - } - } - -exit: - return found; -} - -static inline bool forbid_system_uid(uid_t uid) { - #define SHELL_UID 2000 - #define SYSTEM_UID 1000 - return uid < SHELL_UID && uid != SYSTEM_UID; -} - -static bool profile_valid(struct app_profile *profile) -{ - if (!profile) { - return false; - } - - if (profile->version < KSU_APP_PROFILE_VER) { - pr_info("Unsupported profile version: %d\n", profile->version); - return false; - } - - if (profile->allow_su) { - if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) { - return false; - } - - if (strlen(profile->rp_config.profile.selinux_domain) == 0) { - return false; - } - } - - return true; -} - -bool ksu_set_app_profile(struct app_profile *profile, bool persist) -{ - struct perm_data *p = NULL; - struct list_head *pos = NULL; - bool result = false; - - if (!profile_valid(profile)) { - pr_err("Failed to set app profile: invalid profile!\n"); - return false; - } - - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - // both uid and package must match, otherwise it will break multiple package with different user id - if (profile->current_uid == p->profile.current_uid && - !strcmp(profile->key, p->profile.key)) { - // found it, just override it all! - memcpy(&p->profile, profile, sizeof(*profile)); - result = true; - goto out; - } - } - - // not found, alloc a new node! - p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL); - if (!p) { - pr_err("ksu_set_app_profile alloc failed\n"); - return false; - } - - memcpy(&p->profile, profile, sizeof(*profile)); - if (profile->allow_su) { - pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n", - profile->key, profile->current_uid, - profile->rp_config.profile.gid, - profile->rp_config.profile.selinux_domain); - } else { - pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n", - profile->key, profile->current_uid, - profile->nrp_config.profile.umount_modules); - } - list_add_tail(&p->list, &allow_list); - -out: - if (profile->current_uid <= BITMAP_UID_MAX) { - if (profile->allow_su) - allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE); - else - allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE)); - } else { - if (profile->allow_su) { - /* - * 1024 apps with uid higher than BITMAP_UID_MAX - * registered to request superuser? - */ - if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) { - pr_err("too many apps registered\n"); - WARN_ON(1); - return false; - } - allow_list_arr[allow_list_pointer++] = profile->current_uid; - } else { - remove_uid_from_arr(profile->current_uid); - } - } - result = true; - - // check if the default profiles is changed, cache it to a single struct to accelerate access. - if (unlikely(!strcmp(profile->key, "$"))) { - // set default non root profile - memcpy(&default_non_root_profile, &profile->nrp_config.profile, - sizeof(default_non_root_profile)); - } - - if (unlikely(!strcmp(profile->key, "#"))) { - // set default root profile - memcpy(&default_root_profile, &profile->rp_config.profile, - sizeof(default_root_profile)); - } - - if (persist) - persistent_allow_list(); - - return result; -} - -bool __ksu_is_allow_uid(uid_t uid) -{ - int i; - - if (unlikely(uid == 0)) { - // already root, but only allow our domain. - return ksu_is_ksu_domain(); - } - - if (forbid_system_uid(uid)) { - // do not bother going through the list if it's system - return false; - } - - if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) { - // manager is always allowed! - return true; - } - - if (likely(uid <= BITMAP_UID_MAX)) { - return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE))); - } else { - for (i = 0; i < allow_list_pointer; i++) { - if (allow_list_arr[i] == uid) - return true; - } - } - - return false; -} - -bool ksu_uid_should_umount(uid_t uid) -{ - struct app_profile profile = { .current_uid = uid }; - if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) { - // we should not umount on manager! - return false; - } - bool found = ksu_get_app_profile(&profile); - if (!found) { - // no app profile found, it must be non root app - return default_non_root_profile.umount_modules; - } - if (profile.allow_su) { - // if found and it is granted to su, we shouldn't umount for it - return false; - } else { - // found an app profile - if (profile.nrp_config.use_default) { - return default_non_root_profile.umount_modules; - } else { - return profile.nrp_config.profile.umount_modules; - } - } -} - -struct root_profile *ksu_get_root_profile(uid_t uid) -{ - struct perm_data *p = NULL; - struct list_head *pos = NULL; - - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - if (uid == p->profile.current_uid && p->profile.allow_su) { - if (!p->profile.rp_config.use_default) { - return &p->profile.rp_config.profile; - } - } - } - - // use default profile - return &default_root_profile; -} - -bool ksu_get_allow_list(int *array, int *length, bool allow) -{ - struct perm_data *p = NULL; - struct list_head *pos = NULL; - int i = 0; - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - // pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow); - if (p->profile.allow_su == allow) { - array[i++] = p->profile.current_uid; - } - } - *length = i; - - return true; -} - -static void do_save_allow_list(struct work_struct *work) -{ - u32 magic = FILE_MAGIC; - u32 version = FILE_FORMAT_VERSION; - struct perm_data *p = NULL; - struct list_head *pos = NULL; - loff_t off = 0; - - struct file *fp = - ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (IS_ERR(fp)) { - pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp)); - return; - } - - // store magic and version - if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != - sizeof(magic)) { - pr_err("save_allow_list write magic failed.\n"); - goto exit; - } - - if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != - sizeof(version)) { - pr_err("save_allow_list write version failed.\n"); - goto exit; - } - - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - pr_info("save allow list, name: %s uid :%d, allow: %d\n", - p->profile.key, p->profile.current_uid, - p->profile.allow_su); - - ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile), - &off); - } - -exit: - filp_close(fp, 0); -} - -static void do_load_allow_list(struct work_struct *work) -{ - loff_t off = 0; - ssize_t ret = 0; - struct file *fp = NULL; - u32 magic; - u32 version; - -#ifdef CONFIG_KSU_DEBUG - // always allow adb shell by default - ksu_grant_root_to_shell(); -#endif - - // load allowlist now! - fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp)); - return; - } - - // verify magic - if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != - sizeof(magic) || - magic != FILE_MAGIC) { - pr_err("allowlist file invalid: %d!\n", magic); - goto exit; - } - - if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != - sizeof(version)) { - pr_err("allowlist read version: %d failed\n", version); - goto exit; - } - - pr_info("allowlist version: %d\n", version); - - while (true) { - struct app_profile profile; - - ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile), - &off); - - if (ret <= 0) { - pr_info("load_allow_list read err: %zd\n", ret); - break; - } - - pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", - profile.key, profile.current_uid, profile.allow_su); - ksu_set_app_profile(&profile, false); - } - -exit: - ksu_show_allow_list(); - filp_close(fp, 0); -} - -void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data) -{ - struct perm_data *np = NULL; - struct perm_data *n = NULL; - - bool modified = false; - // TODO: use RCU! - mutex_lock(&allowlist_mutex); - list_for_each_entry_safe (np, n, &allow_list, list) { - uid_t uid = np->profile.current_uid; - char *package = np->profile.key; - // we use this uid for special cases, don't prune it! - bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID; - if (!is_preserved_uid && !is_uid_valid(uid, package, data)) { - modified = true; - pr_info("prune uid: %d, package: %s\n", uid, package); - list_del(&np->list); - if (likely(uid <= BITMAP_UID_MAX)) { - allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE)); - } - remove_uid_from_arr(uid); - smp_mb(); - kfree(np); - } - } - mutex_unlock(&allowlist_mutex); - - if (modified) { - persistent_allow_list(); - } -} - -// make sure allow list works cross boot -static bool persistent_allow_list(void) -{ - return ksu_queue_work(&ksu_save_work); -} - -bool ksu_load_allow_list(void) -{ - return ksu_queue_work(&ksu_load_work); -} - -void ksu_allowlist_init(void) -{ - int i; - - BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE); - BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE); - - for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++) - allow_list_arr[i] = -1; - - INIT_LIST_HEAD(&allow_list); - - INIT_WORK(&ksu_save_work, do_save_allow_list); - INIT_WORK(&ksu_load_work, do_load_allow_list); - - init_default_profiles(); -} - -void ksu_allowlist_exit(void) -{ - struct perm_data *np = NULL; - struct perm_data *n = NULL; - - do_save_allow_list(NULL); - - // free allowlist - mutex_lock(&allowlist_mutex); - list_for_each_entry_safe (np, n, &allow_list, list) { - list_del(&np->list); - kfree(np); - } - mutex_unlock(&allowlist_mutex); -} diff --git a/drivers/staging/kernelsu/allowlist.h b/drivers/staging/kernelsu/allowlist.h deleted file mode 100644 index e89bf71fa10c..000000000000 --- a/drivers/staging/kernelsu/allowlist.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __KSU_H_ALLOWLIST -#define __KSU_H_ALLOWLIST - -#include -#include "ksu.h" - -void ksu_allowlist_init(void); - -void ksu_allowlist_exit(void); - -bool ksu_load_allow_list(void); - -void ksu_show_allow_list(void); - -bool __ksu_is_allow_uid(uid_t uid); -#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid)) - -bool ksu_get_allow_list(int *array, int *length, bool allow); - -void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void *data); - -bool ksu_get_app_profile(struct app_profile *); -bool ksu_set_app_profile(struct app_profile *, bool persist); - -bool ksu_uid_should_umount(uid_t uid); -struct root_profile *ksu_get_root_profile(uid_t uid); -#endif diff --git a/drivers/staging/kernelsu/apk_sign.c b/drivers/staging/kernelsu/apk_sign.c deleted file mode 100644 index 1c758d72e3de..000000000000 --- a/drivers/staging/kernelsu/apk_sign.c +++ /dev/null @@ -1,393 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) -#include -#else -#include -#endif - -#include "apk_sign.h" -#include "klog.h" // IWYU pragma: keep -#include "kernel_compat.h" -#include "throne_tracker.h" - -static unsigned int expected_manager_size = EXPECTED_MANAGER_SIZE; -static char expected_manager_hash[SHA256_DIGEST_SIZE * 2 + 1] = EXPECTED_MANAGER_HASH; - -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static struct sdesc *init_sdesc(struct crypto_shash *alg) -{ - struct sdesc *sdesc; - int size; - - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - return sdesc; -} - -static int calc_hash(struct crypto_shash *alg, const unsigned char *data, - unsigned int datalen, unsigned char *digest) -{ - struct sdesc *sdesc; - int ret; - - sdesc = init_sdesc(alg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc sdesc\n"); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); - kfree(sdesc); - return ret; -} - -static int ksu_sha256(const unsigned char *data, unsigned int datalen, - unsigned char *digest) -{ - struct crypto_shash *alg; - char *hash_alg_name = "sha256"; - int ret; - - alg = crypto_alloc_shash(hash_alg_name, 0, 0); - if (IS_ERR(alg)) { - pr_info("can't alloc alg %s\n", hash_alg_name); - return PTR_ERR(alg); - } - ret = calc_hash(alg, data, datalen, digest); - crypto_free_shash(alg); - return ret; -} - -static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, - unsigned expected_size, const char *expected_sha256) -{ - ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length - ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length - ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length - - *offset += 0x4 * 3; - - ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length - - *pos += *size4; - *offset += 0x4 + *size4; - - ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length - ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length - *offset += 0x4 * 2; - - if (*size4 == expected_size) { - *offset += *size4; - -#define CERT_MAX_LENGTH 1024 - char cert[CERT_MAX_LENGTH]; - if (*size4 > CERT_MAX_LENGTH) { - pr_info("cert length overlimit\n"); - return false; - } - ksu_kernel_read_compat(fp, cert, *size4, pos); - unsigned char digest[SHA256_DIGEST_SIZE]; - if (IS_ERR(ksu_sha256(cert, *size4, digest))) { - pr_info("sha256 error\n"); - return false; - } - - char hash_str[SHA256_DIGEST_SIZE * 2 + 1]; - hash_str[SHA256_DIGEST_SIZE * 2] = '\0'; - - bin2hex(hash_str, digest, SHA256_DIGEST_SIZE); - pr_info("sha256: %s, expected: %s\n", hash_str, - expected_sha256); - if (strcmp(expected_sha256, hash_str) == 0) { - return true; - } - } - return false; -} - -struct zip_entry_header { - uint32_t signature; - uint16_t version; - uint16_t flags; - uint16_t compression; - uint16_t mod_time; - uint16_t mod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t file_name_length; - uint16_t extra_field_length; -} __attribute__((packed)); - -// This is a necessary but not sufficient condition, but it is enough for us -static bool has_v1_signature_file(struct file *fp) -{ - struct zip_entry_header header; - const char MANIFEST[] = "META-INF/MANIFEST.MF"; - - loff_t pos = 0; - - while (ksu_kernel_read_compat(fp, &header, - sizeof(struct zip_entry_header), &pos) == - sizeof(struct zip_entry_header)) { - if (header.signature != 0x04034b50) { - // ZIP magic: 'PK' - return false; - } - // Read the entry file name - if (header.file_name_length == sizeof(MANIFEST) - 1) { - char fileName[sizeof(MANIFEST)]; - ksu_kernel_read_compat(fp, fileName, - header.file_name_length, &pos); - fileName[header.file_name_length] = '\0'; - - // Check if the entry matches META-INF/MANIFEST.MF - if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) == - 0) { - return true; - } - } else { - // Skip the entry file name - pos += header.file_name_length; - } - - // Skip to the next entry - pos += header.extra_field_length + header.compressed_size; - } - - return false; -} - -static __always_inline bool check_v2_signature(char *path, - unsigned expected_size, - const char *expected_sha256) -{ - unsigned char buffer[0x11] = { 0 }; - u32 size4; - u64 size8, size_of_block; - - loff_t pos; - - bool v2_signing_valid = false; - int v2_signing_blocks = 0; - bool v3_signing_exist = false; - bool v3_1_signing_exist = false; - - int i; - struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0); - if (IS_ERR(fp)) { - pr_err("open %s error.\n", path); - return false; - } - - // disable inotify for this file - fp->f_mode |= FMODE_NONOTIFY; - - // https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD) - for (i = 0;; ++i) { - unsigned short n; - pos = generic_file_llseek(fp, -i - 2, SEEK_END); - ksu_kernel_read_compat(fp, &n, 2, &pos); - if (n == i) { - pos -= 22; - ksu_kernel_read_compat(fp, &size4, 4, &pos); - if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) { - break; - } - } - if (i == 0xffff) { - pr_info("error: cannot find eocd\n"); - goto clean; - } - } - - pos += 12; - // offset - ksu_kernel_read_compat(fp, &size4, 0x4, &pos); - pos = size4 - 0x18; - - ksu_kernel_read_compat(fp, &size8, 0x8, &pos); - ksu_kernel_read_compat(fp, buffer, 0x10, &pos); - if (strcmp((char *)buffer, "APK Sig Block 42")) { - goto clean; - } - - pos = size4 - (size8 + 0x8); - ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos); - if (size_of_block != size8) { - goto clean; - } - - int loop_count = 0; - while (loop_count++ < 10) { - uint32_t id; - uint32_t offset; - ksu_kernel_read_compat(fp, &size8, 0x8, - &pos); // sequence length - if (size8 == size_of_block) { - break; - } - ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id - offset = 4; - if (id == 0x7109871au) { - v2_signing_blocks++; - v2_signing_valid = - check_block(fp, &size4, &pos, &offset, - expected_size, expected_sha256); - } else if (id == 0xf05368c0u) { - // http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#73 - v3_signing_exist = true; - } else if (id == 0x1b93ad61u) { - // http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#74 - v3_1_signing_exist = true; - } else { -#ifdef CONFIG_KSU_DEBUG - pr_info("Unknown id: 0x%08x\n", id); -#endif - } - pos += (size8 - offset); - } - - if (v2_signing_blocks != 1) { -#ifdef CONFIG_KSU_DEBUG - pr_err("Unexpected v2 signature count: %d\n", - v2_signing_blocks); -#endif - v2_signing_valid = false; - } - - if (v2_signing_valid) { - int has_v1_signing = has_v1_signature_file(fp); - if (has_v1_signing) { - pr_err("Unexpected v1 signature scheme found!\n"); - filp_close(fp, 0); - return false; - } - } -clean: - filp_close(fp, 0); - - if (v3_signing_exist || v3_1_signing_exist) { -#ifdef CONFIG_KSU_DEBUG - pr_err("Unexpected v3 signature scheme found!\n"); -#endif - return false; - } - - return v2_signing_valid; -} - -#ifdef CONFIG_KSU_DEBUG - -int ksu_debug_manager_uid = -1; - -#include "manager.h" - -static int set_expected_size(const char *val, const struct kernel_param *kp) -{ - int rv = param_set_uint(val, kp); - ksu_set_manager_uid(ksu_debug_manager_uid); - pr_info("ksu_manager_uid set to %d\n", ksu_debug_manager_uid); - return rv; -} - -static struct kernel_param_ops expected_size_ops = { - .set = set_expected_size, - .get = param_get_uint, -}; - -module_param_cb(ksu_debug_manager_uid, &expected_size_ops, - &ksu_debug_manager_uid, S_IRUSR | S_IWUSR); - -#else - -static int set_expected_size(const char *val, const struct kernel_param *kp) -{ - int rv = param_set_uint(val, kp); - pr_info("expected_manager_size set to %u\n", expected_manager_size); - return rv; -} - -static int get_expected_size(char *buf, const struct kernel_param *kp) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", expected_manager_size); -} - -static int set_expected_hash(const char *val, const struct kernel_param *kp) -{ - if (strlen(val) != SHA256_DIGEST_SIZE * 2) { - pr_err("Invalid hash length: %s\n", val); - return -EINVAL; - } - - strncpy(expected_manager_hash, val, SHA256_DIGEST_SIZE * 2); - expected_manager_hash[SHA256_DIGEST_SIZE * 2] = '\0'; - - pr_info("expected_manager_hash set to %s\n", expected_manager_hash); - return 0; -} - -static int get_expected_hash(char *buf, const struct kernel_param *kp) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", expected_manager_hash); -} - -static struct kernel_param_ops expected_size_ops = { - .set = set_expected_size, - .get = get_expected_size, -}; - -static struct kernel_param_ops expected_hash_ops = { - .set = set_expected_hash, - .get = get_expected_hash, -}; - -module_param_cb(expected_manager_size, &expected_size_ops, &expected_manager_size, 0644); - -module_param_cb(expected_manager_hash, &expected_hash_ops, &expected_manager_hash, 0644); - -#endif - -bool ksu_is_manager_apk(char *path) -{ - int tries = 0; - - while (tries++ < 10) { - if (!is_lock_held(path)) - break; - - pr_info("%s: waiting for %s\n", __func__, path); - msleep(100); - } - - // let it go, if retry fails, check_v2_signature will fail to open it anyway - if (tries == 10) { - pr_info("%s: timeout for %s\n", __func__, path); - return false; - } - - // set debug info to print size and hash to kernel log - pr_info("%s: expected size: %u, expected hash: %s\n", - path, expected_manager_size, expected_manager_hash); - -#ifdef CONFIG_KSU_DEBUG - return check_v2_signature(path, EXPECTED_MANAGER_SIZE, EXPECTED_MANAGER_HASH); -#else - return check_v2_signature(path, expected_manager_size, expected_manager_hash); -#endif -} diff --git a/drivers/staging/kernelsu/apk_sign.h b/drivers/staging/kernelsu/apk_sign.h deleted file mode 100644 index e02aa5144065..000000000000 --- a/drivers/staging/kernelsu/apk_sign.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __KSU_H_APK_V2_SIGN -#define __KSU_H_APK_V2_SIGN - -#include - -bool ksu_is_manager_apk(char *path); - -#endif diff --git a/drivers/staging/kernelsu/arch.h b/drivers/staging/kernelsu/arch.h deleted file mode 100644 index f36ec5f509fa..000000000000 --- a/drivers/staging/kernelsu/arch.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __KSU_H_ARCH -#define __KSU_H_ARCH - -#include - -#if defined(__aarch64__) - -#define __PT_PARM1_REG regs[0] -#define __PT_PARM2_REG regs[1] -#define __PT_PARM3_REG regs[2] -#define __PT_SYSCALL_PARM4_REG regs[3] -#define __PT_CCALL_PARM4_REG regs[3] -#define __PT_PARM5_REG regs[4] -#define __PT_PARM6_REG regs[5] -#define __PT_RET_REG regs[30] -#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */ -#define __PT_RC_REG regs[0] -#define __PT_SP_REG sp -#define __PT_IP_REG pc - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) -#define PRCTL_SYMBOL "__arm64_sys_prctl" -#define SYS_READ_SYMBOL "__arm64_sys_read" -#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat" -#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat" -#define SYS_EXECVE_SYMBOL "__arm64_sys_execve" -#else -#define PRCTL_SYMBOL "sys_prctl" -#define SYS_READ_SYMBOL "sys_read" -#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat" -#define SYS_FACCESSAT_SYMBOL "sys_faccessat" -#define SYS_EXECVE_SYMBOL "sys_execve" -#endif - -#elif defined(__x86_64__) - -#define __PT_PARM1_REG di -#define __PT_PARM2_REG si -#define __PT_PARM3_REG dx -/* syscall uses r10 for PARM4 */ -#define __PT_SYSCALL_PARM4_REG r10 -#define __PT_CCALL_PARM4_REG cx -#define __PT_PARM5_REG r8 -#define __PT_PARM6_REG r9 -#define __PT_RET_REG sp -#define __PT_FP_REG bp -#define __PT_RC_REG ax -#define __PT_SP_REG sp -#define __PT_IP_REG ip -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) -#define PRCTL_SYMBOL "__x64_sys_prctl" -#define SYS_READ_SYMBOL "__x64_sys_read" -#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat" -#define SYS_FACCESSAT_SYMBOL "__x64_sys_faccessat" -#define SYS_EXECVE_SYMBOL "__x64_sys_execve" -#else -#define PRCTL_SYMBOL "sys_prctl" -#define SYS_READ_SYMBOL "sys_read" -#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat" -#define SYS_FACCESSAT_SYMBOL "sys_faccessat" -#define SYS_EXECVE_SYMBOL "sys_execve" -#endif - -#else -#error "Unsupported arch" -#endif - -/* allow some architecutres to override `struct pt_regs` */ -#ifndef __PT_REGS_CAST -#define __PT_REGS_CAST(x) (x) -#endif - -#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG) -#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG) -#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG) -#define PT_REGS_SYSCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_SYSCALL_PARM4_REG) -#define PT_REGS_CCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_CCALL_PARM4_REG) -#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG) -#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG) -#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG) -#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG) -#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG) -#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG) -#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG) - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) -#define PT_REAL_REGS(regs) ((struct pt_regs *)PT_REGS_PARM1(regs)) -#else -#define PT_REAL_REGS(regs) ((regs)) -#endif - -#endif diff --git a/drivers/staging/kernelsu/core_hook.c b/drivers/staging/kernelsu/core_hook.c deleted file mode 100644 index a9f524c87088..000000000000 --- a/drivers/staging/kernelsu/core_hook.c +++ /dev/null @@ -1,1535 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KSU_LSM_SECURITY_HOOKS -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef MODULE -#include -#include -#include -#include -#include -#endif - -#ifdef CONFIG_KSU_SUSFS -#include -#endif // #ifdef CONFIG_KSU_SUSFS - -#include "allowlist.h" -#include "arch.h" -#include "core_hook.h" -#include "klog.h" // IWYU pragma: keep -#include "ksu.h" -#include "ksud.h" -#include "manager.h" -#include "selinux/selinux.h" -#include "throne_tracker.h" -#include "kernel_compat.h" - -#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_ENABLE_LOG -extern bool susfs_is_log_enabled __read_mostly; -#endif -#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; -static bool susfs_is_umount_for_zygote_iso_service_enabled = false; -extern bool susfs_hide_sus_mnts_for_all_procs; -#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 -} -#endif // #ifdef CONFIG_KSU_SUSFS - -static bool ksu_module_mounted = false; - -extern int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4); - -bool ksu_su_compat_enabled = true; -extern void ksu_sucompat_init(); -extern void ksu_sucompat_exit(); - -static inline bool is_allow_su() -{ - if (ksu_is_manager()) { - // we are manager, allow! - return true; - } - return ksu_is_allow_uid(current_uid().val); -} - -static inline bool is_unsupported_uid(uid_t uid) -{ -#define LAST_APPLICATION_UID 19999 - uid_t appid = uid % 100000; - return appid > LAST_APPLICATION_UID; -} - -static struct group_info root_groups = { .usage = ATOMIC_INIT(2) }; - -static void setup_groups(struct root_profile *profile, struct cred *cred) -{ - if (profile->groups_count > KSU_MAX_GROUPS) { - pr_warn("Failed to setgroups, too large group: %d!\n", - profile->uid); - return; - } - - if (profile->groups_count == 1 && profile->groups[0] == 0) { - // setgroup to root and return early. - if (cred->group_info) - put_group_info(cred->group_info); - cred->group_info = get_group_info(&root_groups); - return; - } - - u32 ngroups = profile->groups_count; - struct group_info *group_info = groups_alloc(ngroups); - if (!group_info) { - pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid); - return; - } - - int i; - for (i = 0; i < ngroups; i++) { - gid_t gid = profile->groups[i]; - kgid_t kgid = make_kgid(current_user_ns(), gid); - if (!gid_valid(kgid)) { - pr_warn("Failed to setgroups, invalid gid: %d\n", gid); - put_group_info(group_info); - return; - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) - group_info->gid[i] = kgid; -#else - GROUP_AT(group_info, i) = kgid; -#endif - } - - groups_sort(group_info); - set_groups(cred, group_info); - put_group_info(group_info); -} - -static void disable_seccomp(void) -{ - assert_spin_locked(¤t->sighand->siglock); - // disable seccomp -#if defined(CONFIG_GENERIC_ENTRY) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) - current_thread_info()->syscall_work &= ~SYSCALL_WORK_SECCOMP; -#else - current_thread_info()->flags &= ~(TIF_SECCOMP | _TIF_SECCOMP); -#endif - -#ifdef CONFIG_SECCOMP - current->seccomp.mode = 0; - current->seccomp.filter = NULL; -#else -#endif -} - -void ksu_escape_to_root(void) -{ - struct cred *cred; - - cred = prepare_creds(); - if (!cred) { - pr_warn("prepare_creds failed!\n"); - return; - } - - if (cred->euid.val == 0) { - pr_warn("Already root, don't escape!\n"); - abort_creds(cred); - return; - } - - struct root_profile *profile = ksu_get_root_profile(cred->uid.val); - - cred->uid.val = profile->uid; - cred->suid.val = profile->uid; - cred->euid.val = profile->uid; - cred->fsuid.val = profile->uid; - - cred->gid.val = profile->gid; - cred->fsgid.val = profile->gid; - cred->sgid.val = profile->gid; - cred->egid.val = profile->gid; - cred->securebits = 0; - - BUILD_BUG_ON(sizeof(profile->capabilities.effective) != - sizeof(kernel_cap_t)); - - // setup capabilities - // we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process - // we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec! - u64 cap_for_ksud = - profile->capabilities.effective | CAP_DAC_READ_SEARCH; - memcpy(&cred->cap_effective, &cap_for_ksud, - sizeof(cred->cap_effective)); - memcpy(&cred->cap_permitted, &profile->capabilities.effective, - sizeof(cred->cap_permitted)); - memcpy(&cred->cap_bset, &profile->capabilities.effective, - sizeof(cred->cap_bset)); - // set ambient caps to all-zero - // fixes "operation not permitted" on dbus cap dropping - memset(&cred->cap_ambient, 0, - sizeof(cred->cap_ambient)); - - setup_groups(profile, cred); - - commit_creds(cred); - - // Refer to kernel/seccomp.c: seccomp_set_mode_strict - // When disabling Seccomp, ensure that current->sighand->siglock is held during the operation. - spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(); - spin_unlock_irq(¤t->sighand->siglock); - - ksu_setup_selinux(profile->selinux_domain); -} - -int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) -{ - if (!current->mm) { - // skip kernel threads - return 0; - } - - if (current_uid().val != 1000) { - // skip non system uid - return 0; - } - - if (!old_dentry || !new_dentry) { - return 0; - } - - // /data/system/packages.list.tmp -> /data/system/packages.list - if (strcmp(new_dentry->d_iname, "packages.list")) { - return 0; - } - - char path[128]; - char *buf = dentry_path_raw(new_dentry, path, sizeof(path)); - if (IS_ERR(buf)) { - pr_err("dentry_path_raw failed.\n"); - return 0; - } - - if (!strstr(buf, "/system/packages.list")) { - return 0; - } - pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname, - new_dentry->d_iname, buf); - - ksu_track_throne(); - - return 0; -} - -static void nuke_ext4_sysfs() { - struct path path; - int err = kern_path("/data/adb/modules", 0, &path); - if (err) { - pr_err("nuke path err: %d\n", err); - return; - } - - struct super_block* sb = path.dentry->d_inode->i_sb; - const char* name = sb->s_type->name; - if (strcmp(name, "ext4") != 0) { - pr_info("nuke but module aren't mounted\n"); - path_put(&path); - return; - } - - ext4_unregister_sysfs(sb); - path_put(&path); -} - -int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) -{ - // if success, we modify the arg5 as result! - u32 *result = (u32 *)arg5; - u32 reply_ok = KERNEL_SU_OPTION; - - if (KERNEL_SU_OPTION != option) { - return 0; - } - - // TODO: find it in throne tracker! - uid_t current_uid_val = current_uid().val; - uid_t manager_uid = ksu_get_manager_uid(); - if (current_uid_val != manager_uid && - current_uid_val % 100000 == manager_uid) { - ksu_set_manager_uid(current_uid_val); - } - - bool from_root = 0 == current_uid().val; - bool from_manager = ksu_is_manager(); - - if (!from_root && !from_manager) { - // only root or manager can access this interface - return 0; - } - -#ifdef CONFIG_KSU_DEBUG - pr_info("option: 0x%x, cmd: %ld\n", option, arg2); -#endif - - if (arg2 == CMD_BECOME_MANAGER) { - if (from_manager) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("become_manager: prctl reply error\n"); - } - return 0; - } - return 0; - } - - if (arg2 == CMD_GRANT_ROOT) { - if (is_allow_su()) { - pr_info("allow root for: %d\n", current_uid().val); - ksu_escape_to_root(); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("grant_root: prctl reply error\n"); - } - } - return 0; - } - - // Both root manager and root processes should be allowed to get version - if (arg2 == CMD_GET_VERSION) { - u32 version = KERNEL_SU_VERSION; - if (copy_to_user(arg3, &version, sizeof(version))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - u32 version_flags = 0; -#ifdef MODULE - version_flags |= 0x1; -#endif - if (arg4 && - copy_to_user(arg4, &version_flags, sizeof(version_flags))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - if (arg2 == CMD_GET_MANAGER_UID) { - uid_t manager_uid = ksu_get_manager_uid(); - if (copy_to_user(arg3, &manager_uid, sizeof(manager_uid))) { - pr_err("get manager uid failed\n"); - } - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - if (arg2 == CMD_HOOK_MODE) { -#ifdef CONFIG_KSU_KPROBES_HOOK - const char *mode = "Kprobes"; -#else - const char *mode = "Manual"; -#endif - if (copy_to_user((void __user *)arg3, mode, strlen(mode) + 1)) { - pr_info("hook: copy_to_user() failed\n"); - } - return 0; - } - - if (arg2 == CMD_REPORT_EVENT) { - if (!from_root) { - return 0; - } - 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"); - ksu_on_post_fs_data(); - } - break; - } - case EVENT_BOOT_COMPLETED: { - static bool boot_complete_lock = false; - if (!boot_complete_lock) { - boot_complete_lock = true; - pr_info("boot_complete triggered\n"); - } - break; - } - case EVENT_MODULE_MOUNTED: { - ksu_module_mounted = true; - pr_info("module mounted!\n"); - nuke_ext4_sysfs(); - break; - } - default: - break; - } - return 0; - } - - if (arg2 == CMD_SET_SEPOLICY) { - if (!from_root) { - return 0; - } - if (!ksu_handle_sepolicy(arg3, arg4)) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("sepolicy: prctl reply error\n"); - } - } - - return 0; - } - - if (arg2 == CMD_CHECK_SAFEMODE) { - if (ksu_is_safe_mode()) { - pr_warn("safemode enabled!\n"); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("safemode: prctl reply error\n"); - } - } - return 0; - } - - if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) { - u32 array[128]; - u32 array_length; - bool success = ksu_get_allow_list(array, &array_length, - arg2 == CMD_GET_ALLOW_LIST); - if (success) { - if (!copy_to_user(arg4, &array_length, - sizeof(array_length)) && - !copy_to_user(arg3, array, - sizeof(u32) * array_length)) { - if (copy_to_user(result, &reply_ok, - sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", - arg2); - } - } else { - pr_err("prctl copy allowlist error\n"); - } - } - return 0; - } - - if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) { - uid_t target_uid = (uid_t)arg3; - bool allow = false; - if (arg2 == CMD_UID_GRANTED_ROOT) { - allow = ksu_is_allow_uid(target_uid); - } else if (arg2 == CMD_UID_SHOULD_UMOUNT) { - allow = ksu_uid_should_umount(target_uid); - } else { - pr_err("unknown cmd: %lu\n", arg2); - } - if (!copy_to_user(arg4, &allow, sizeof(allow))) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - } else { - pr_err("prctl copy err, cmd: %lu\n", arg2); - } - 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; - } - if (arg2 == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) { - int error = 0; - if (!ksu_access_ok((void __user*)arg3, SUSFS_MAX_LEN_PATHNAME)) { - pr_err("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> arg3 is not accessible\n"); - return 0; - } - if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { - pr_err("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> arg5 is not accessible\n"); - return 0; - } - error = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH); - pr_info("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_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; - } - if (arg2 == CMD_SUSFS_SET_SDCARD_ROOT_PATH) { - int error = 0; - if (!ksu_access_ok((void __user*)arg3, SUSFS_MAX_LEN_PATHNAME)) { - pr_err("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> arg3 is not accessible\n"); - return 0; - } - if (!ksu_access_ok((void __user*)arg5, sizeof(error))) { - pr_err("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> arg5 is not accessible\n"); - return 0; - } - error = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_SDCARD_ROOT_PATH); - pr_info("susfs: CMD_SUSFS_SET_SDCARD_ROOT_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; - } - if (arg2 == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) { - int error = 0; - if (arg3 != 0 && arg3 != 1) { - pr_err("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> arg3 can only be 0 or 1\n"); - return 0; - } - susfs_hide_sus_mnts_for_all_procs = arg3; - pr_info("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> susfs_hide_sus_mnts_for_all_procs: %lu\n", arg3); - if (copy_to_user((void __user*)arg5, &error, sizeof(error))) - pr_info("susfs: copy_to_user() failed\n"); - return 0; - } - if (arg2 == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) { - int error = 0; - if (arg3 != 0 && arg3 != 1) { - pr_err("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> arg3 can only be 0 or 1\n"); - return 0; - } - susfs_is_umount_for_zygote_iso_service_enabled = arg3; - pr_info("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> susfs_is_umount_for_zygote_iso_service_enabled: %lu\n", 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_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; - if (arg4 <= 0) { - pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg4 cannot be <= 0\n"); - return 0; - } - if (!ksu_access_ok((void __user*)arg3, arg4)) { - 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; - } - error = susfs_get_enabled_features((char __user*)arg3, arg4); - 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; - } - - // we are already manager - if (arg2 == CMD_GET_APP_PROFILE) { - struct app_profile profile; - if (copy_from_user(&profile, arg3, sizeof(profile))) { - pr_err("copy profile failed\n"); - return 0; - } - - bool success = ksu_get_app_profile(&profile); - if (success) { - if (copy_to_user(arg3, &profile, sizeof(profile))) { - pr_err("copy profile failed\n"); - return 0; - } - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - } - return 0; - } - - if (arg2 == CMD_SET_APP_PROFILE) { - struct app_profile profile; - if (copy_from_user(&profile, arg3, sizeof(profile))) { - pr_err("copy profile failed\n"); - return 0; - } - - // todo: validate the params - if (ksu_set_app_profile(&profile, true)) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - } - return 0; - } - - if (arg2 == CMD_IS_SU_ENABLED) { - if (copy_to_user(arg3, &ksu_su_compat_enabled, - sizeof(ksu_su_compat_enabled))) { - pr_err("copy su compat failed\n"); - return 0; - } - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - if (arg2 == CMD_ENABLE_SU) { - bool enabled = (arg3 != 0); - if (enabled == ksu_su_compat_enabled) { - pr_info("cmd enable su but no need to change.\n"); - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {// return the reply_ok directly - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - return 0; - } - - if (enabled) { -#ifdef CONFIG_KSU_SUSFS_SUS_SU - // We disable all sus_su hook whenever user toggle on su_kps - susfs_is_sus_su_hooks_enabled = false; - ksu_devpts_hook = false; - susfs_sus_su_working_mode = SUS_SU_DISABLED; -#endif - ksu_sucompat_init(); - } else { - ksu_sucompat_exit(); - } - ksu_su_compat_enabled = enabled; - - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("prctl reply error, cmd: %lu\n", arg2); - } - - return 0; - } - - return 0; -} - -static bool is_appuid(kuid_t uid) -{ -#define PER_USER_RANGE 100000 -#define FIRST_APPLICATION_UID 10000 -#define LAST_APPLICATION_UID 19999 - - uid_t appid = uid.val % PER_USER_RANGE; - return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID; -} - -static bool should_umount(struct path *path) -{ - if (!path) { - return false; - } - - if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) { - pr_info("ignore global mnt namespace process: %d\n", - current_uid().val); - 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) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_UMOUNT) - return path_umount(path, flags); -#else - // TODO: umount for non GKI kernel - return -ENOSYS; -#endif -} - -#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT -void ksu_try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid) -#else -static void ksu_try_umount(const char *mnt, bool check_mnt, int flags) -#endif -{ - struct path path; - int err = kern_path(mnt, 0, &path); - if (err) { - return; - } - - if (path.dentry != path.mnt->mnt_root) { - // it is not root mountpoint, maybe umounted by others already. - path_put(&path); - return; - } - - // we are only interest in some specific mounts - if (check_mnt && !should_umount(&path)) { - path_put(&path); - return; - } - -#if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG) - if (susfs_is_log_enabled) { - pr_info("susfs: umounting '%s' for uid: %d\n", mnt, uid); - } -#endif - - err = ksu_umount_mnt(&path, flags); - if (err) { - pr_warn("umount %s failed: %d\n", mnt, err); - } -} - -#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, uid); - ksu_try_umount("/system_ext", true, 0, uid); - ksu_try_umount("/vendor", true, 0, uid); - ksu_try_umount("/product", true, 0, uid); - ksu_try_umount("/odm", 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 - ksu_try_umount("/data/adb/modules", false, MNT_DETACH, uid); - /* For both Legacy KSU and Magic Mount KSU */ - ksu_try_umount("/debug_ramdisk", true, MNT_DETACH, uid); - - // try umount ksu temp path - ksu_try_umount("/sbin", false, MNT_DETACH, uid); - - // try umount hosts file - ksu_try_umount("/system/etc/hosts", false, MNT_DETACH, uid); - - // try umount lsposed dex2oat bins - ksu_try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid); - ksu_try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid); -} -#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! - 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; - } - -#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_ksu_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 - task_unlock(current); -#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 - } - } -#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); - return 0; - } - - if (ksu_is_allow_uid(new_uid.val)) { - // pr_info("handle setuid ignore allowed application: %d\n", new_uid.val); - 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); - } -#endif // #ifdef CONFIG_KSU_SUSFS - -#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT -out_ksu_try_umount: -#endif - if (!ksu_uid_should_umount(new_uid.val)) { - return 0; - } else { -#ifdef CONFIG_KSU_DEBUG - 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 - 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` - ksu_try_umount("/odm", true, 0); - 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 - ksu_try_umount("/debug_ramdisk", false, MNT_DETACH); - ksu_try_umount("/sbin", false, MNT_DETACH); - - // try umount hosts file - ksu_try_umount("/system/etc/hosts", false, MNT_DETACH); - - // try umount lsposed dex2oat bins - ksu_try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH); - ksu_try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH); -#endif - - return 0; -} - -// Init functons - -static int handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int option = (int)PT_REGS_PARM1(real_regs); - unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs); - unsigned long arg3 = (unsigned long)PT_REGS_PARM3(real_regs); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) - // PRCTL_SYMBOL is the arch-specificed one, which receive raw pt_regs from syscall - unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs); -#else - // PRCTL_SYMBOL is the common one, called by C convention in do_syscall_64 - // https://elixir.bootlin.com/linux/v4.15.18/source/arch/x86/entry/common.c#L287 - unsigned long arg4 = (unsigned long)PT_REGS_CCALL_PARM4(real_regs); -#endif - unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs); - - return ksu_handle_prctl(option, arg2, arg3, arg4, arg5); -} - -static struct kprobe prctl_kp = { - .symbol_name = PRCTL_SYMBOL, - .pre_handler = handler_pre, -}; - -static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) - // https://elixir.bootlin.com/linux/v5.12-rc1/source/include/linux/fs.h - struct renamedata *rd = PT_REGS_PARM1(regs); - struct dentry *old_entry = rd->old_dentry; - struct dentry *new_entry = rd->new_dentry; -#else - struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs); - struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs); -#endif - - return ksu_handle_rename(old_entry, new_entry); -} - -static struct kprobe renameat_kp = { - .symbol_name = "vfs_rename", - .pre_handler = renameat_handler_pre, -}; - -__maybe_unused int ksu_kprobe_init(void) -{ - int rc = 0; - rc = register_kprobe(&prctl_kp); - - if (rc) { - pr_info("prctl kprobe failed: %d.\n", rc); - return rc; - } - - rc = register_kprobe(&renameat_kp); - pr_info("renameat kp: %d\n", rc); - - return rc; -} - -__maybe_unused int ksu_kprobe_exit(void) -{ - unregister_kprobe(&prctl_kp); - unregister_kprobe(&renameat_kp); - return 0; -} - -extern int ksu_handle_devpts(struct inode *inode); // sucompat.c - -static int ksu_inode_permission(struct inode *inode, int mask) -{ - if (unlikely(inode->i_sb && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)) { -#ifdef CONFIG_KSU_DEBUG - pr_info("%s: devpts inode accessed with mask: %x\n", __func__, mask); -#endif - ksu_handle_devpts(inode); - } - return 0; -} - -// kernel 4.9 and older -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) -int ksu_key_permission(key_ref_t key_ref, const struct cred *cred, - unsigned perm) -{ - if (init_session_keyring != NULL) { - return 0; - } - if (strcmp(current->comm, "init")) { - // we are only interested in `init` process - return 0; - } - init_session_keyring = cred->session_keyring; - pr_info("kernel_compat: got init_session_keyring\n"); - return 0; -} -#endif - -#ifdef CONFIG_KSU_LSM_SECURITY_HOOKS -static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) -{ - ksu_handle_prctl(option, arg2, arg3, arg4, arg5); - return -ENOSYS; -} - -static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) -{ - return ksu_handle_rename(old_dentry, new_dentry); -} - -static int ksu_task_fix_setuid(struct cred *new, const struct cred *old, - int flags) -{ - return ksu_handle_setuid(new, old); -} - -#ifndef MODULE -static struct security_hook_list ksu_hooks[] = { - LSM_HOOK_INIT(task_prctl, ksu_task_prctl), - LSM_HOOK_INIT(inode_rename, ksu_inode_rename), - LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid), - LSM_HOOK_INIT(inode_permission, ksu_inode_permission), -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) - LSM_HOOK_INIT(key_permission, ksu_key_permission) -#endif -}; - -void __init ksu_lsm_hook_init(void) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) - security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), "ksu"); -#else - // https://elixir.bootlin.com/linux/v4.10.17/source/include/linux/lsm_hooks.h#L1892 - security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks)); -#endif -} - -#else -static int override_security_head(void *head, const void *new_head, size_t len) -{ - unsigned long base = (unsigned long)head & PAGE_MASK; - unsigned long offset = offset_in_page(head); - - // this is impossible for our case because the page alignment - // but be careful for other cases! - BUG_ON(offset + len > PAGE_SIZE); - struct page *page = phys_to_page(__pa(base)); - if (!page) { - return -EFAULT; - } - - void *addr = vmap(&page, 1, VM_MAP, PAGE_KERNEL); - if (!addr) { - return -ENOMEM; - } - local_irq_disable(); - memcpy(addr + offset, new_head, len); - local_irq_enable(); - vunmap(addr); - return 0; -} - -static void free_security_hook_list(struct hlist_head *head) -{ - struct hlist_node *temp; - struct security_hook_list *entry; - - if (!head) - return; - - hlist_for_each_entry_safe (entry, temp, head, list) { - hlist_del(&entry->list); - kfree(entry); - } - - kfree(head); -} - -struct hlist_head *copy_security_hlist(struct hlist_head *orig) -{ - struct hlist_head *new_head = kmalloc(sizeof(*new_head), GFP_KERNEL); - if (!new_head) - return NULL; - - INIT_HLIST_HEAD(new_head); - - struct security_hook_list *entry; - struct security_hook_list *new_entry; - - hlist_for_each_entry (entry, orig, list) { - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); - if (!new_entry) { - free_security_hook_list(new_head); - return NULL; - } - - *new_entry = *entry; - - hlist_add_tail_rcu(&new_entry->list, new_head); - } - - return new_head; -} - -#define LSM_SEARCH_MAX 180 // This should be enough to iterate -static void *find_head_addr(void *security_ptr, int *index) -{ - if (!security_ptr) { - return NULL; - } - struct hlist_head *head_start = - (struct hlist_head *)&security_hook_heads; - - for (int i = 0; i < LSM_SEARCH_MAX; i++) { - struct hlist_head *head = head_start + i; - struct security_hook_list *pos; - hlist_for_each_entry (pos, head, list) { - if (pos->hook.capget == security_ptr) { - if (index) { - *index = i; - } - return head; - } - } - } - - return NULL; -} - -#define GET_SYMBOL_ADDR(sym) \ - ({ \ - void *addr = kallsyms_lookup_name(#sym ".cfi_jt"); \ - if (!addr) { \ - addr = kallsyms_lookup_name(#sym); \ - } \ - addr; \ - }) - -#define KSU_LSM_HOOK_HACK_INIT(head_ptr, name, func) \ - do { \ - static struct security_hook_list hook = { \ - .hook = { .name = func } \ - }; \ - hook.head = head_ptr; \ - hook.lsm = "ksu"; \ - struct hlist_head *new_head = copy_security_hlist(hook.head); \ - if (!new_head) { \ - pr_err("Failed to copy security list: %s\n", #name); \ - break; \ - } \ - hlist_add_tail_rcu(&hook.list, new_head); \ - if (override_security_head(hook.head, new_head, \ - sizeof(*new_head))) { \ - free_security_hook_list(new_head); \ - pr_err("Failed to hack lsm for: %s\n", #name); \ - } \ - } while (0) - -void __init ksu_lsm_hook_init(void) -{ - void *cap_prctl = GET_SYMBOL_ADDR(cap_task_prctl); - void *prctl_head = find_head_addr(cap_prctl, NULL); - if (prctl_head) { - if (prctl_head != &security_hook_heads.task_prctl) { - pr_warn("prctl's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(prctl_head, task_prctl, ksu_task_prctl); - } else { - pr_warn("Failed to find task_prctl!\n"); - } - - int inode_killpriv_index = -1; - void *cap_killpriv = GET_SYMBOL_ADDR(cap_inode_killpriv); - find_head_addr(cap_killpriv, &inode_killpriv_index); - if (inode_killpriv_index < 0) { - pr_warn("Failed to find inode_rename, use kprobe instead!\n"); - register_kprobe(&renameat_kp); - } else { - int inode_rename_index = inode_killpriv_index + - &security_hook_heads.inode_rename - - &security_hook_heads.inode_killpriv; - struct hlist_head *head_start = - (struct hlist_head *)&security_hook_heads; - void *inode_rename_head = head_start + inode_rename_index; - if (inode_rename_head != &security_hook_heads.inode_rename) { - pr_warn("inode_rename's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(inode_rename_head, inode_rename, - ksu_inode_rename); - } - void *cap_setuid = GET_SYMBOL_ADDR(cap_task_fix_setuid); - void *setuid_head = find_head_addr(cap_setuid, NULL); - if (setuid_head) { - if (setuid_head != &security_hook_heads.task_fix_setuid) { - pr_warn("setuid's address has shifted!\n"); - } - KSU_LSM_HOOK_HACK_INIT(setuid_head, task_fix_setuid, - ksu_task_fix_setuid); - } else { - pr_warn("Failed to find task_fix_setuid!\n"); - } - smp_mb(); -} -#endif // MODULE -#endif // CONFIG_KSU_LSM_SECURITY_HOOKS - -void __init ksu_core_init(void) -{ -#ifdef CONFIG_KSU_LSM_SECURITY_HOOKS - ksu_lsm_hook_init(); -#else - pr_info("ksu_core_init: LSM hooks not in use.\n"); -#endif -} - -void ksu_core_exit(void) -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - pr_info("ksu_core_kprobe_exit\n"); - // we dont use this now - // ksu_kprobe_exit(); -#endif -} diff --git a/drivers/staging/kernelsu/core_hook.h b/drivers/staging/kernelsu/core_hook.h deleted file mode 100644 index 616951e8db35..000000000000 --- a/drivers/staging/kernelsu/core_hook.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __KSU_H_KSU_CORE -#define __KSU_H_KSU_CORE - -#include - -void __init ksu_core_init(void); -void ksu_core_exit(void); - -#endif diff --git a/drivers/staging/kernelsu/embed_ksud.c b/drivers/staging/kernelsu/embed_ksud.c deleted file mode 100644 index 24c401219c15..000000000000 --- a/drivers/staging/kernelsu/embed_ksud.c +++ /dev/null @@ -1,5 +0,0 @@ -// WARNING: THIS IS A STUB FILE -// This file will be regenerated by CI - -unsigned int ksud_size = 0; -const char ksud[0] = {}; diff --git a/drivers/staging/kernelsu/export_symbol.txt b/drivers/staging/kernelsu/export_symbol.txt deleted file mode 100644 index 1abd805e8e6a..000000000000 --- a/drivers/staging/kernelsu/export_symbol.txt +++ /dev/null @@ -1,2 +0,0 @@ -register_kprobe -unregister_kprobe diff --git a/drivers/staging/kernelsu/include/ksu_hook.h b/drivers/staging/kernelsu/include/ksu_hook.h deleted file mode 100644 index ea0b04d3e538..000000000000 --- a/drivers/staging/kernelsu/include/ksu_hook.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __KSU_H_KSHOOK -#define __KSU_H_KSHOOK - -#include -#include - -// For sucompat - -int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *flags); - -int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); - -// For ksud - -int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, - size_t *count_ptr, loff_t **pos); - -// For ksud and sucompat - -int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags); - -// For volume button -int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, - int *value); - -#endif diff --git a/drivers/staging/kernelsu/kernel_compat.c b/drivers/staging/kernelsu/kernel_compat.c deleted file mode 100644 index 267d150c5947..000000000000 --- a/drivers/staging/kernelsu/kernel_compat.c +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) -#include -#else -#include -#endif -#include -#include "klog.h" // IWYU pragma: keep -#include "kernel_compat.h" // Add check Huawei Device -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) -#include -#include -#include -struct key *init_session_keyring = NULL; - -static inline int install_session_keyring(struct key *keyring) -{ - struct cred *new; - int ret; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - ret = install_session_keyring_to_cred(new, keyring); - if (ret < 0) { - abort_creds(new); - return ret; - } - - return commit_creds(new); -} -#endif - -extern struct task_struct init_task; - -// mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA -struct ksu_ns_fs_saved { - struct nsproxy *ns; - struct fs_struct *fs; -}; - -static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved) -{ - ns_fs_saved->ns = current->nsproxy; - ns_fs_saved->fs = current->fs; -} - -static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved) -{ - current->nsproxy = ns_fs_saved->ns; - current->fs = ns_fs_saved->fs; -} - -static bool android_context_saved_checked = false; -static bool android_context_saved_enabled = false; -static struct ksu_ns_fs_saved android_context_saved; - -void ksu_android_ns_fs_check() -{ - if (android_context_saved_checked) - return; - android_context_saved_checked = true; - task_lock(current); - if (current->nsproxy && current->fs && - current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) { - android_context_saved_enabled = true; - pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n", - current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns); - ksu_save_ns_fs(&android_context_saved); - } else { - pr_info("android context saved disabled\n"); - } - 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) - if (init_session_keyring != NULL && !current_cred()->session_keyring && - (current->flags & PF_WQ_WORKER)) { - pr_info("installing init session keyring for older kernel\n"); - install_session_keyring(init_session_keyring); - } -#endif - // switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns - struct ksu_ns_fs_saved saved; - if (android_context_saved_enabled) { - pr_info("start switch current nsproxy and fs to android context\n"); - task_lock(current); - ksu_save_ns_fs(&saved); - ksu_load_ns_fs(&android_context_saved); - task_unlock(current); - } - struct file *fp = filp_open(filename, flags, mode); - if (android_context_saved_enabled) { - task_lock(current); - ksu_load_ns_fs(&saved); - task_unlock(current); - pr_info("switch current nsproxy and fs back to saved successfully\n"); - } - return fp; -} - -ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, - loff_t *pos) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || defined(KSU_KERNEL_READ) - return kernel_read(p, buf, count, pos); -#else - loff_t offset = pos ? *pos : 0; - ssize_t result = kernel_read(p, offset, (char *)buf, count); - if (pos && result > 0) { - *pos = offset + result; - } - return result; -#endif -} - -ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, - loff_t *pos) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || defined(KSU_KERNEL_WRITE) - return kernel_write(p, buf, count, pos); -#else - loff_t offset = pos ? *pos : 0; - ssize_t result = kernel_write(p, buf, count, offset); - if (pos && result > 0) { - *pos = offset + result; - } - return result; -#endif -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) || defined(KSU_STRNCPY_FROM_USER_NOFAULT) -long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) -{ - return strncpy_from_user_nofault(dst, unsafe_addr, count); -} -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) -long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) -{ - return strncpy_from_unsafe_user(dst, unsafe_addr, count); -} -#else -// Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201 -long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, - long count) -{ - mm_segment_t old_fs = get_fs(); - long ret; - - if (unlikely(count <= 0)) - return 0; - - set_fs(USER_DS); - pagefault_disable(); - ret = strncpy_from_user(dst, unsafe_addr, count); - pagefault_enable(); - set_fs(old_fs); - - if (ret >= count) { - ret = count; - dst[ret - 1] = '\0'; - } else if (ret > 0) { - ret++; - } - - return ret; -} -#endif - -long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr, - long count) -{ - long ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count); - if (likely(ret >= 0)) - return ret; - - // we faulted! fallback to slow path - if (unlikely(!ksu_access_ok(unsafe_addr, count))) - return -EFAULT; - - return strncpy_from_user(dst, unsafe_addr, count); -} diff --git a/drivers/staging/kernelsu/kernel_compat.h b/drivers/staging/kernelsu/kernel_compat.h deleted file mode 100644 index cad307a00513..000000000000 --- a/drivers/staging/kernelsu/kernel_compat.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __KSU_H_KERNEL_COMPAT -#define __KSU_H_KERNEL_COMPAT - -#include -#include -#include "ss/policydb.h" -#include "linux/key.h" - -/* - * Adapt to Huawei HISI kernel without affecting other kernels , - * Huawei Hisi Kernel EBITMAP Enable or Disable Flag , - * From ss/ebitmap.h - */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) -#ifdef HISI_SELINUX_EBITMAP_RO -#define CONFIG_IS_HW_HISI -#endif -#endif - -extern long ksu_strncpy_from_user_nofault(char *dst, - const void __user *unsafe_addr, - long count); -extern long ksu_strncpy_from_user_retry(char *dst, - const void __user *unsafe_addr, - long count); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) -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, - loff_t *pos); -extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, - size_t count, loff_t *pos); - -#endif diff --git a/drivers/staging/kernelsu/klog.h b/drivers/staging/kernelsu/klog.h deleted file mode 100644 index a934027fbeeb..000000000000 --- a/drivers/staging/kernelsu/klog.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __KSU_H_KLOG -#define __KSU_H_KLOG - -#include - -#ifdef pr_fmt -#undef pr_fmt -#define pr_fmt(fmt) "KernelSU: " fmt -#endif - -#endif diff --git a/drivers/staging/kernelsu/ksu.c b/drivers/staging/kernelsu/ksu.c deleted file mode 100644 index a8a02c2f68cf..000000000000 --- a/drivers/staging/kernelsu/ksu.c +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include -#include -#include - -#include "allowlist.h" -#include "arch.h" -#include "core_hook.h" -#include "klog.h" // IWYU pragma: keep -#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) -{ - return queue_work(ksu_workqueue, work); -} - -extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags); - -extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags); - -int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags) -{ - ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags); - return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, - flags); -} - -extern void ksu_sucompat_init(); -extern void ksu_sucompat_exit(); -extern void ksu_ksud_init(); -extern void ksu_ksud_exit(); - -int __init ksu_kernelsu_init(void) -{ -#ifdef CONFIG_KSU_DEBUG - pr_alert("*************************************************************"); - pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); - pr_alert("** **"); - pr_alert("** You are running KernelSU in DEBUG mode **"); - pr_alert("** **"); - pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); - pr_alert("*************************************************************"); -#endif - -#ifdef CONFIG_KSU_SUSFS - susfs_init(); -#endif - - ksu_core_init(); - - ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0); - - ksu_allowlist_init(); - - ksu_throne_tracker_init(); - -#ifdef CONFIG_KSU_KPROBES_HOOK - ksu_sucompat_init(); - ksu_ksud_init(); -#else - pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html"); -#endif - -#ifdef MODULE -#ifndef CONFIG_KSU_DEBUG - kobject_del(&THIS_MODULE->mkobj.kobj); -#endif -#endif - return 0; -} - -void ksu_kernelsu_exit(void) -{ - ksu_allowlist_exit(); - - ksu_throne_tracker_exit(); - - destroy_workqueue(ksu_workqueue); - -#ifdef CONFIG_KSU_KPROBES_HOOK - ksu_ksud_exit(); - ksu_sucompat_exit(); -#endif - - ksu_core_exit(); -} - -module_init(ksu_kernelsu_init); -module_exit(ksu_kernelsu_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("weishu"); -MODULE_DESCRIPTION("Android KernelSU"); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) -MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); -#endif diff --git a/drivers/staging/kernelsu/ksu.h b/drivers/staging/kernelsu/ksu.h deleted file mode 100644 index 5101c695ea62..000000000000 --- a/drivers/staging/kernelsu/ksu.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __KSU_H_KSU -#define __KSU_H_KSU - -#include -#include - -#define KERNEL_SU_VERSION KSU_VERSION -#define KERNEL_SU_OPTION 0xDEADBEEF - -#define CMD_GRANT_ROOT 0 -#define CMD_BECOME_MANAGER 1 -#define CMD_GET_VERSION 2 -#define CMD_ALLOW_SU 3 -#define CMD_DENY_SU 4 -#define CMD_GET_ALLOW_LIST 5 -#define CMD_GET_DENY_LIST 6 -#define CMD_REPORT_EVENT 7 -#define CMD_SET_SEPOLICY 8 -#define CMD_CHECK_SAFEMODE 9 -#define CMD_GET_APP_PROFILE 10 -#define CMD_SET_APP_PROFILE 11 -#define CMD_UID_GRANTED_ROOT 12 -#define CMD_UID_SHOULD_UMOUNT 13 -#define CMD_IS_SU_ENABLED 14 -#define CMD_ENABLE_SU 15 -#define CMD_GET_MANAGER_UID 16 - -#define CMD_HOOK_MODE 0xC0DEAD1A - -#define EVENT_POST_FS_DATA 1 -#define EVENT_BOOT_COMPLETED 2 -#define EVENT_MODULE_MOUNTED 3 - -#define KSU_APP_PROFILE_VER 2 -#define KSU_MAX_PACKAGE_NAME 256 -// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups. -#define KSU_MAX_GROUPS 32 -#define KSU_SELINUX_DOMAIN 64 - -struct root_profile { - int32_t uid; - int32_t gid; - - int32_t groups_count; - int32_t groups[KSU_MAX_GROUPS]; - - // kernel_cap_t is u32[2] for capabilities v3 - struct { - u64 effective; - u64 permitted; - u64 inheritable; - } capabilities; - - char selinux_domain[KSU_SELINUX_DOMAIN]; - - int32_t namespaces; -}; - -struct non_root_profile { - bool umount_modules; -}; - -struct app_profile { - // It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this. - u32 version; - - // this is usually the package of the app, but can be other value for special apps - char key[KSU_MAX_PACKAGE_NAME]; - int32_t current_uid; - bool allow_su; - - union { - struct { - bool use_default; - char template_name[KSU_MAX_PACKAGE_NAME]; - - struct root_profile profile; - } rp_config; - - struct { - bool use_default; - - struct non_root_profile profile; - } nrp_config; - }; -}; - -bool ksu_queue_work(struct work_struct *work); - -static inline int startswith(char *s, char *prefix) -{ - return strncmp(s, prefix, strlen(prefix)); -} - -static inline int endswith(const char *s, const char *t) -{ - size_t slen = strlen(s); - size_t tlen = strlen(t); - if (tlen > slen) - return 1; - return strcmp(s + slen - tlen, t); -} - -#endif diff --git a/drivers/staging/kernelsu/ksud.c b/drivers/staging/kernelsu/ksud.c deleted file mode 100644 index b8c4f1fb88a8..000000000000 --- a/drivers/staging/kernelsu/ksud.c +++ /dev/null @@ -1,737 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) -#include -#else -#include -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) -#include -#endif -#include -#include -#include -#include -#include - -#include "allowlist.h" -#include "arch.h" -#include "klog.h" // IWYU pragma: keep -#include "ksud.h" -#include "kernel_compat.h" -#include "selinux/selinux.h" - -static const char KERNEL_SU_RC[] = - "\n" - - "on post-fs-data\n" - " start logd\n" - // We should wait for the post-fs-data finish - " exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n" - "\n" - - "on nonencrypted\n" - " exec u:r:su:s0 root -- " KSUD_PATH " services\n" - "\n" - - "on property:vold.decrypt=trigger_restart_framework\n" - " exec u:r:su:s0 root -- " KSUD_PATH " services\n" - "\n" - - "on property:sys.boot_completed=1\n" - " exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n" - "\n" - - "\n"; - -static void stop_vfs_read_hook(); -static void stop_execve_hook(); -static void stop_input_hook(); - -#ifdef CONFIG_KSU_KPROBES_HOOK -static struct work_struct stop_vfs_read_work; -static struct work_struct stop_execve_hook_work; -static struct work_struct stop_input_hook_work; -#else -bool ksu_vfs_read_hook __read_mostly = true; -bool ksu_execveat_hook __read_mostly = true; -bool ksu_input_hook __read_mostly = true; -#endif - -#ifdef CONFIG_KSU_SUSFS_SUS_SU -bool susfs_is_sus_su_ready = false; -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU - -u32 ksu_devpts_sid; - -#ifdef CONFIG_COMPAT -bool ksu_is_compat __read_mostly = false; -#endif - -void ksu_on_post_fs_data(void) -{ - static bool done = false; - if (done) { - pr_info("ksu_on_post_fs_data already done\n"); - return; - } - done = true; - pr_info("ksu_on_post_fs_data!\n"); - ksu_load_allow_list(); - // sanity check, this may influence the performance - stop_input_hook(); - - ksu_devpts_sid = ksu_get_devpts_sid(); - pr_info("devpts sid: %d\n", ksu_devpts_sid); -} - -#define MAX_ARG_STRINGS 0x7FFFFFFF -struct user_arg_ptr { -#ifdef CONFIG_COMPAT - bool is_compat; -#endif - union { - const char __user *const __user *native; -#ifdef CONFIG_COMPAT - const compat_uptr_t __user *compat; -#endif - } ptr; -}; - -static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) -{ - const char __user *native; - -#ifdef CONFIG_COMPAT - if (unlikely(argv.is_compat)) { - compat_uptr_t compat; - - if (get_user(compat, argv.ptr.compat + nr)) - return ERR_PTR(-EFAULT); - - ksu_is_compat = true; - return compat_ptr(compat); - } -#endif - - if (get_user(native, argv.ptr.native + nr)) - return ERR_PTR(-EFAULT); - - return native; -} - -/* - * count() counts the number of strings in array ARGV. - */ - -/* - * Make sure old GCC compiler can use __maybe_unused, - * Test passed in 4.4.x ~ 4.9.x when use GCC. - */ - -static int __maybe_unused count(struct user_arg_ptr argv, int max) -{ - int i = 0; - - if (argv.ptr.native != NULL) { - for (;;) { - const char __user *p = get_user_arg_ptr(argv, i); - - if (!p) - break; - - if (IS_ERR(p)) - return -EFAULT; - - if (i >= max) - return -E2BIG; - ++i; - - if (fatal_signal_pending(current)) - return -ERESTARTNOHAND; - cond_resched(); - } - } - return i; -} - -// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version -int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, - struct user_arg_ptr *argv, - struct user_arg_ptr *envp, int *flags) -{ -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_execveat_hook) { - return 0; - } -#endif - struct filename *filename; - - static const char app_process[] = "/system/bin/app_process"; - static bool first_app_process = true; - - /* This applies to versions Android 10+ */ - static const char system_bin_init[] = "/system/bin/init"; - /* This applies to versions between Android 6 ~ 9 */ - static const char old_system_init[] = "/init"; - static bool init_second_stage_executed = false; - - if (!filename_ptr) - return 0; - - filename = *filename_ptr; - if (IS_ERR(filename)) { - return 0; - } - - if (unlikely(!memcmp(filename->name, system_bin_init, - sizeof(system_bin_init) - 1) && - argv)) { - // /system/bin/init executed - int argc = count(*argv, MAX_ARG_STRINGS); - pr_info("/system/bin/init argc: %d\n", argc); - if (argc > 1 && !init_second_stage_executed) { - const char __user *p = get_user_arg_ptr(*argv, 1); - if (p && !IS_ERR(p)) { - char first_arg[16]; - ksu_strncpy_from_user_retry( - first_arg, p, sizeof(first_arg)); - pr_info("/system/bin/init first arg: %s\n", - first_arg); - if (!strcmp(first_arg, "second_stage")) { - pr_info("/system/bin/init second_stage executed\n"); - ksu_apply_kernelsu_rules(); - init_second_stage_executed = true; - ksu_android_ns_fs_check(); - } - } else { - pr_err("/system/bin/init parse args err!\n"); - } - } - } else if (unlikely(!memcmp(filename->name, old_system_init, - sizeof(old_system_init) - 1) && - argv)) { - // /init executed - int argc = count(*argv, MAX_ARG_STRINGS); - pr_info("/init argc: %d\n", argc); - if (argc > 1 && !init_second_stage_executed) { - /* This applies to versions between Android 6 ~ 7 */ - const char __user *p = get_user_arg_ptr(*argv, 1); - if (p && !IS_ERR(p)) { - char first_arg[16]; - ksu_strncpy_from_user_retry( - first_arg, p, sizeof(first_arg)); - pr_info("/init first arg: %s\n", first_arg); - if (!strcmp(first_arg, "--second-stage")) { - pr_info("/init second_stage executed\n"); - ksu_apply_kernelsu_rules(); - init_second_stage_executed = true; - ksu_android_ns_fs_check(); - } - } else { - pr_err("/init parse args err!\n"); - } - } else if (argc == 1 && !init_second_stage_executed && envp) { - /* This applies to versions between Android 8 ~ 9 */ - int envc = count(*envp, MAX_ARG_STRINGS); - if (envc > 0) { - int n; - for (n = 1; n <= envc; n++) { - const char __user *p = - get_user_arg_ptr(*envp, n); - if (!p || IS_ERR(p)) { - continue; - } - char env[256]; - // Reading environment variable strings from user space - if (ksu_strncpy_from_user_retry( - env, p, sizeof(env)) < 0) - continue; - // Parsing environment variable names and values - char *env_name = env; - char *env_value = strchr(env, '='); - if (env_value == NULL) - continue; - // Replace equal sign with string terminator - *env_value = '\0'; - env_value++; - // Check if the environment variable name and value are matching - if (!strcmp(env_name, - "INIT_SECOND_STAGE") && - (!strcmp(env_value, "1") || - !strcmp(env_value, "true"))) { - pr_info("/init second_stage executed\n"); - ksu_apply_kernelsu_rules(); - init_second_stage_executed = - true; - ksu_android_ns_fs_check(); - } - } - } - } - } - - if (unlikely(first_app_process && !memcmp(filename->name, app_process, - sizeof(app_process) - 1))) { - first_app_process = false; - pr_info("exec app_process, /data prepared, second_stage: %d\n", - init_second_stage_executed); - ksu_on_post_fs_data(); // we keep this for old ksud - stop_execve_hook(); - } - - return 0; -} - -static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *); -static ssize_t (*orig_read_iter)(struct kiocb *, struct iov_iter *); -static struct file_operations fops_proxy; -static ssize_t read_count_append = 0; - -static ssize_t read_proxy(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - bool first_read = file->f_pos == 0; - ssize_t ret = orig_read(file, buf, count, pos); - if (first_read) { - pr_info("read_proxy append %ld + %ld\n", ret, - read_count_append); - ret += read_count_append; - } - return ret; -} - -static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to) -{ - bool first_read = iocb->ki_pos == 0; - ssize_t ret = orig_read_iter(iocb, to); - if (first_read) { - pr_info("read_iter_proxy append %ld + %ld\n", ret, - read_count_append); - ret += read_count_append; - } - return ret; -} - -int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, - size_t *count_ptr, loff_t **pos) -{ -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_vfs_read_hook) { - return 0; - } -#endif - struct file *file; - char __user *buf; - size_t count; - - if (strcmp(current->comm, "init")) { - // we are only interest in `init` process - return 0; - } - - file = *file_ptr; - if (IS_ERR(file)) { - return 0; - } - - if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) { - return 0; - } - - const char *short_name = file->f_path.dentry->d_name.name; - if (strcmp(short_name, "atrace.rc")) { - // we are only interest `atrace.rc` file name file - return 0; - } - char path[256]; - char *dpath = d_path(&file->f_path, path, sizeof(path)); - - if (IS_ERR(dpath)) { - return 0; - } - - if (strcmp(dpath, "/system/etc/init/atrace.rc")) { - return 0; - } - - // we only process the first read - static bool rc_inserted = false; - if (rc_inserted) { - // we don't need this kprobe, unregister it! - stop_vfs_read_hook(); - return 0; - } - rc_inserted = true; - - // now we can sure that the init process is reading - // `/system/etc/init/atrace.rc` - buf = *buf_ptr; - count = *count_ptr; - - size_t rc_count = strlen(KERNEL_SU_RC); - - pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath, - current->comm, count, rc_count); - - if (count < rc_count) { - pr_err("count: %zu < rc_count: %zu\n", count, rc_count); - return 0; - } - - size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count); - if (ret) { - pr_err("copy ksud.rc failed: %zu\n", ret); - return 0; - } - - // we've succeed to insert ksud.rc, now we need to proxy the read and modify the result! - // But, we can not modify the file_operations directly, because it's in read-only memory. - // We just replace the whole file_operations with a proxy one. - memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations)); - orig_read = file->f_op->read; - if (orig_read) { - fops_proxy.read = read_proxy; - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) - orig_read_iter = file->f_op->read_iter; - if (orig_read_iter) { - fops_proxy.read_iter = read_iter_proxy; - } -#endif - // replace the file_operations - file->f_op = &fops_proxy; - read_count_append = rc_count; - - *buf_ptr = buf + rc_count; - *count_ptr = count - rc_count; - - return 0; -} - -int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, - size_t *count_ptr) -{ - struct file *file = fget(fd); - if (!file) { - return 0; - } - int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL); - fput(file); - return result; -} - -static unsigned int volumedown_pressed_count = 0; - -static bool is_volumedown_enough(unsigned int count) -{ - return count >= 3; -} - -int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, - int *value) -{ -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_input_hook) { - return 0; - } -#endif - if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) { - int val = *value; - pr_info("KEY_VOLUMEDOWN val: %d\n", val); - if (val) { - // key pressed, count it - volumedown_pressed_count += 1; - if (is_volumedown_enough(volumedown_pressed_count)) { - stop_input_hook(); - } - } - } - - return 0; -} - -bool ksu_is_safe_mode() -{ - static bool safe_mode = false; - if (safe_mode) { - // don't need to check again, userspace may call multiple times - return true; - } - - // stop hook first! - stop_input_hook(); - - pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count); - if (is_volumedown_enough(volumedown_pressed_count)) { - // pressed over 3 times - pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n"); - safe_mode = true; - return true; - } - - return false; -} - -/* - * ksu_handle_execve_ksud, execve_ksud handler for non kprobe - * adapted from sys_execve_handler_pre - * https://github.com/tiann/KernelSU/commit/2027ac3 - */ -__maybe_unused int ksu_handle_execve_ksud(const char __user *filename_user, - const char __user *const __user *__argv) -{ - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct filename filename_in, *filename_p; - char path[32]; - -#ifndef CONFIG_KSU_KPROBES_HOOK - // return early if disabled. - if (!ksu_execveat_hook) { - return 0; - } -#endif - - if (!filename_user) - return 0; - - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_nofault(path, filename_user, 32); - - // this is because ksu_handle_execveat_ksud calls it filename->name - filename_in.name = path; - filename_p = &filename_in; - - return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, NULL); -} - -#ifdef CONFIG_KSU_KPROBES_HOOK - -// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864 -static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - int *fd = (int *)&PT_REGS_PARM1(regs); - struct filename **filename_ptr = - (struct filename **)&PT_REGS_PARM2(regs); - struct user_arg_ptr argv; -#ifdef CONFIG_COMPAT - argv.is_compat = PT_REGS_PARM3(regs); - if (unlikely(argv.is_compat)) { - argv.ptr.compat = PT_REGS_CCALL_PARM4(regs); - } else { - argv.ptr.native = PT_REGS_CCALL_PARM4(regs); - } -#else - argv.ptr.native = PT_REGS_PARM3(regs); -#endif - - return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL); -} - -static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM1(real_regs); - const char __user *const __user *__argv = - (const char __user *const __user *)PT_REGS_PARM2(real_regs); - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct filename filename_in, *filename_p; - char path[32]; - - if (!filename_user) - return 0; - - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_nofault(path, *filename_user, 32); - filename_in.name = path; - - filename_p = &filename_in; - return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, - NULL); -} - -// remove this later! -__maybe_unused static int vfs_read_handler_pre(struct kprobe *p, - struct pt_regs *regs) -{ - struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs); - char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs); - size_t *count_ptr = (size_t *)&PT_REGS_PARM3(regs); - loff_t **pos_ptr = (loff_t **)&PT_REGS_CCALL_PARM4(regs); - - return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr); -} - -static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - unsigned int fd = PT_REGS_PARM1(real_regs); - char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs); - size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs); - - return ksu_handle_sys_read(fd, buf_ptr, count_ptr); -} - -static int input_handle_event_handler_pre(struct kprobe *p, - struct pt_regs *regs) -{ - unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs); - unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs); - int *value = (int *)&PT_REGS_CCALL_PARM4(regs); - return ksu_handle_input_handle_event(type, code, value); -} - -#if 1 -static struct kprobe execve_kp = { - .symbol_name = SYS_EXECVE_SYMBOL, - .pre_handler = sys_execve_handler_pre, -}; -#else -static struct kprobe execve_kp = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - .symbol_name = "do_execveat_common", -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) - .symbol_name = "__do_execve_file", -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) - .symbol_name = "do_execveat_common", -#endif - .pre_handler = execve_handler_pre, -}; -#endif - -#if 1 -static struct kprobe vfs_read_kp = { - .symbol_name = SYS_READ_SYMBOL, - .pre_handler = sys_read_handler_pre, -}; -#else -static struct kprobe vfs_read_kp = { - .symbol_name = "vfs_read", - .pre_handler = vfs_read_handler_pre, -}; -#endif - -static struct kprobe input_event_kp = { - .symbol_name = "input_event", - .pre_handler = input_handle_event_handler_pre, -}; - -static void do_stop_vfs_read_hook(struct work_struct *work) -{ - unregister_kprobe(&vfs_read_kp); -} - -static void do_stop_execve_hook(struct work_struct *work) -{ - unregister_kprobe(&execve_kp); -} - -static void do_stop_input_hook(struct work_struct *work) -{ - unregister_kprobe(&input_event_kp); -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) -#include "objsec.h" // task_security_struct -bool is_ksu_transition(const struct task_security_struct *old_tsec, - const struct task_security_struct *new_tsec) -{ - static u32 ksu_sid; - char *secdata; - u32 seclen; - bool allowed = false; - - if (!ksu_sid) - security_secctx_to_secid("u:r:su:s0", strlen("u:r:su:s0"), &ksu_sid); - - if (security_secid_to_secctx(old_tsec->sid, &secdata, &seclen)) - return false; - - allowed = (!strcmp("u:r:init:s0", secdata) && new_tsec->sid == ksu_sid); - security_release_secctx(secdata, seclen); - - return allowed; -} -#endif - -static void stop_vfs_read_hook() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - bool ret = schedule_work(&stop_vfs_read_work); - pr_info("unregister vfs_read kprobe: %d!\n", ret); -#else - ksu_vfs_read_hook = false; - pr_info("stop vfs_read_hook\n"); -#endif -} - -static void stop_execve_hook() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - bool ret = schedule_work(&stop_execve_hook_work); - pr_info("unregister execve kprobe: %d!\n", ret); -#else - 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() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - static bool input_hook_stopped = false; - if (input_hook_stopped) { - return; - } - input_hook_stopped = true; - bool ret = schedule_work(&stop_input_hook_work); - pr_info("unregister input kprobe: %d!\n", ret); -#else - if (!ksu_input_hook) { return; } - ksu_input_hook = false; - pr_info("stop input_hook\n"); -#endif -} - -// ksud: module support -void ksu_ksud_init() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - int ret; - - ret = register_kprobe(&execve_kp); - pr_info("ksud: execve_kp: %d\n", ret); - - ret = register_kprobe(&vfs_read_kp); - pr_info("ksud: vfs_read_kp: %d\n", ret); - - ret = register_kprobe(&input_event_kp); - pr_info("ksud: input_event_kp: %d\n", ret); - - INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook); - INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook); - INIT_WORK(&stop_input_hook_work, do_stop_input_hook); -#endif -} - -void ksu_ksud_exit() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - unregister_kprobe(&execve_kp); - // this should be done before unregister vfs_read_kp - // unregister_kprobe(&vfs_read_kp); - unregister_kprobe(&input_event_kp); -#endif -} diff --git a/drivers/staging/kernelsu/ksud.h b/drivers/staging/kernelsu/ksud.h deleted file mode 100644 index 26974c9c4fe5..000000000000 --- a/drivers/staging/kernelsu/ksud.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __KSU_H_KSUD -#define __KSU_H_KSUD - -#include - -#define KSUD_PATH "/data/adb/ksud" - -void ksu_on_post_fs_data(void); - -bool ksu_is_safe_mode(void); - -extern u32 ksu_devpts_sid; - -#endif diff --git a/drivers/staging/kernelsu/manager.h b/drivers/staging/kernelsu/manager.h deleted file mode 100644 index 93fa26786a3a..000000000000 --- a/drivers/staging/kernelsu/manager.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __KSU_H_KSU_MANAGER -#define __KSU_H_KSU_MANAGER - -#include -#include - -#define KSU_INVALID_UID -1 - -extern uid_t ksu_manager_uid; // DO NOT DIRECT USE - -static inline bool ksu_is_manager_uid_valid() -{ - return ksu_manager_uid != KSU_INVALID_UID; -} - -static inline bool ksu_is_manager() -{ - return unlikely(ksu_manager_uid == current_uid().val); -} - -static inline uid_t ksu_get_manager_uid() -{ - return ksu_manager_uid; -} - -static inline void ksu_set_manager_uid(uid_t uid) -{ - ksu_manager_uid = uid; -} - -static inline void ksu_invalidate_manager_uid() -{ - ksu_manager_uid = KSU_INVALID_UID; -} - -#endif diff --git a/drivers/staging/kernelsu/selinux/Makefile b/drivers/staging/kernelsu/selinux/Makefile deleted file mode 100644 index 870750be2ed6..000000000000 --- a/drivers/staging/kernelsu/selinux/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -obj-y += selinux.o -obj-y += sepolicy.o -obj-y += rules.o - -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 += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include -ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h diff --git a/drivers/staging/kernelsu/selinux/rules.c b/drivers/staging/kernelsu/selinux/rules.c deleted file mode 100644 index 5d8326867a29..000000000000 --- a/drivers/staging/kernelsu/selinux/rules.c +++ /dev/null @@ -1,561 +0,0 @@ -#include -#include -#include - -#include "../klog.h" // IWYU pragma: keep -#include "selinux.h" -#include "sepolicy.h" -#include "ss/services.h" -#include "linux/lsm_audit.h" -#include "xfrm.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) -#define SELINUX_POLICY_INSTEAD_SELINUX_SS -#endif - -#define KERNEL_SU_DOMAIN "su" -#define KERNEL_SU_FILE "ksu_file" -#define KERNEL_EXEC_TYPE "ksu_exec" -#define ALL NULL - -static struct policydb *get_policydb(void) -{ - struct policydb *db; -// selinux_state does not exists before 4.19 -#ifdef KSU_COMPAT_USE_SELINUX_STATE -#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS - struct selinux_policy *policy = rcu_dereference(selinux_state.policy); - db = &policy->policydb; -#else - struct selinux_ss *ss = rcu_dereference(selinux_state.ss); - db = &ss->policydb; -#endif -#else - db = &policydb; -#endif - return db; -} - -static DEFINE_MUTEX(ksu_rules); - -void ksu_apply_kernelsu_rules() -{ - struct policydb *db; - - if (!ksu_getenforce()) { - pr_info("SELinux permissive or disabled, apply rules!\n"); - } - - mutex_lock(&ksu_rules); - - db = get_policydb(); - - ksu_permissive(db, KERNEL_SU_DOMAIN); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject"); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain"); - ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain"); - - // Create unconstrained file type - ksu_type(db, KERNEL_SU_FILE, "file_type"); - ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject"); - ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL); - - // allow all! - ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL); - - // allow us do any ioctl - if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) { - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); - ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL); - } - - // we need to save allowlist in /data/adb/ksu - ksu_allow(db, "kernel", "adb_data_file", "dir", ALL); - ksu_allow(db, "kernel", "adb_data_file", "file", ALL); - // we need to search /data/app - ksu_allow(db, "kernel", "apk_data_file", "file", "open"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "open"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "read"); - ksu_allow(db, "kernel", "apk_data_file", "dir", "search"); - // we may need to do mount on shell - ksu_allow(db, "kernel", "shell_data_file", "file", ALL); - // we need to read /data/system/packages.list - ksu_allow(db, "kernel", "kernel", "capability", "dac_override"); - // Android 10+: - // http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512 - ksu_allow(db, "kernel", "packages_list_file", "file", ALL); - // Kernel 4.4 - ksu_allow(db, "kernel", "packages_list_file", "dir", ALL); - // Android 9-: - // http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360 - ksu_allow(db, "kernel", "system_data_file", "file", ALL); - ksu_allow(db, "kernel", "system_data_file", "dir", ALL); - // our ksud triggered by init - ksu_allow(db, "init", "adb_data_file", "file", ALL); - ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289 - ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL); - // we need to umount modules in zygote - ksu_allow(db, "zygote", "adb_data_file", "dir", "search"); - - // copied from Magisk rules - // suRights - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld"); - - // allowLog - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr"); - - // dumpsys - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open"); - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr"); - - // bootctl - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open"); - ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process", - "getattr"); - - // For mounting loop devices, mirrors, tmpfs - ksu_allow(db, "kernel", ALL, "file", "read"); - ksu_allow(db, "kernel", ALL, "file", "write"); - - // Allow all binder transactions - ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL); - - // Allow system server kill su process - 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 - - mutex_unlock(&ksu_rules); -} - -#define MAX_SEPOL_LEN 128 - -#define CMD_NORMAL_PERM 1 -#define CMD_XPERM 2 -#define CMD_TYPE_STATE 3 -#define CMD_TYPE 4 -#define CMD_TYPE_ATTR 5 -#define CMD_ATTR 6 -#define CMD_TYPE_TRANSITION 7 -#define CMD_TYPE_CHANGE 8 -#define CMD_GENFSCON 9 - -#ifdef CONFIG_64BIT -struct sepol_data { - u32 cmd; - u32 subcmd; - u64 field_sepol1; - u64 field_sepol2; - u64 field_sepol3; - u64 field_sepol4; - u64 field_sepol5; - u64 field_sepol6; - u64 field_sepol7; -}; -#ifdef CONFIG_COMPAT -extern bool ksu_is_compat __read_mostly; -struct sepol_compat_data { - u32 cmd; - u32 subcmd; - u32 field_sepol1; - u32 field_sepol2; - u32 field_sepol3; - u32 field_sepol4; - u32 field_sepol5; - u32 field_sepol6; - u32 field_sepol7; -}; -#endif // CONFIG_COMPAT -#else -struct sepol_data { - u32 cmd; - u32 subcmd; - u32 field_sepol1; - u32 field_sepol2; - u32 field_sepol3; - u32 field_sepol4; - u32 field_sepol5; - u32 field_sepol6; - u32 field_sepol7; -}; -#endif // CONFIG_64BIT - -static int get_object(char *buf, char __user *user_object, size_t buf_sz, - char **object) -{ - if (!user_object) { - *object = ALL; - return 0; - } - - if (strncpy_from_user(buf, user_object, buf_sz) < 0) { - return -1; - } - - *object = buf; - - return 0; -} - -// reset avc cache table, otherwise the new rules will not take effect if already denied -static void reset_avc_cache() -{ -#if ((!defined(KSU_COMPAT_USE_SELINUX_STATE)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) - avc_ss_reset(0); - selnl_notify_policyload(0); - selinux_status_update_policyload(0); -#else - struct selinux_avc *avc = selinux_state.avc; - avc_ss_reset(avc, 0); - selnl_notify_policyload(0); - selinux_status_update_policyload(&selinux_state, 0); -#endif - selinux_xfrm_notify_policyload(); -} - -int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4) -{ - if (!arg4) { - return -1; - } - - if (!ksu_getenforce()) { - pr_info("SELinux permissive or disabled when handle policy!\n"); - } - - u32 cmd, subcmd; - char __user *sepol1, *sepol2, *sepol3, *sepol4, *sepol5, *sepol6, *sepol7; - -#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT) - if (unlikely(ksu_is_compat)) { - struct sepol_compat_data compat_data; - if (copy_from_user(&compat_data, arg4, sizeof(struct sepol_compat_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - sepol1 = compat_ptr(compat_data.field_sepol1); - sepol2 = compat_ptr(compat_data.field_sepol2); - sepol3 = compat_ptr(compat_data.field_sepol3); - sepol4 = compat_ptr(compat_data.field_sepol4); - sepol5 = compat_ptr(compat_data.field_sepol5); - sepol6 = compat_ptr(compat_data.field_sepol6); - sepol7 = compat_ptr(compat_data.field_sepol7); - cmd = compat_data.cmd; - subcmd = compat_data.subcmd; - } else { - struct sepol_data data; - if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - sepol1 = data.field_sepol1; - sepol2 = data.field_sepol2; - sepol3 = data.field_sepol3; - sepol4 = data.field_sepol4; - sepol5 = data.field_sepol5; - sepol6 = data.field_sepol6; - sepol7 = data.field_sepol7; - cmd = data.cmd; - subcmd = data.subcmd; - } -#else - // basically for full native, say (64BIT=y COMPAT=n) || (64BIT=n) - struct sepol_data data; - if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - sepol1 = data.field_sepol1; - sepol2 = data.field_sepol2; - sepol3 = data.field_sepol3; - sepol4 = data.field_sepol4; - sepol5 = data.field_sepol5; - sepol6 = data.field_sepol6; - sepol7 = data.field_sepol7; - cmd = data.cmd; - subcmd = data.subcmd; -#endif - - rcu_read_lock(); - - struct policydb *db = get_policydb(); - - int ret = -1; - if (cmd == CMD_NORMAL_PERM) { - char src_buf[MAX_SEPOL_LEN]; - char tgt_buf[MAX_SEPOL_LEN]; - char cls_buf[MAX_SEPOL_LEN]; - char perm_buf[MAX_SEPOL_LEN]; - - char *s, *t, *c, *p; - if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - - if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - - if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - - if (get_object(perm_buf, sepol4, sizeof(perm_buf), &p) < - 0) { - pr_err("sepol: copy perm failed.\n"); - goto exit; - } - - bool success = false; - if (subcmd == 1) { - success = ksu_allow(db, s, t, c, p); - } else if (subcmd == 2) { - success = ksu_deny(db, s, t, c, p); - } else if (subcmd == 3) { - success = ksu_auditallow(db, s, t, c, p); - } else if (subcmd == 4) { - success = ksu_dontaudit(db, s, t, c, p); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - ret = success ? 0 : -1; - - } else if (cmd == CMD_XPERM) { - char src_buf[MAX_SEPOL_LEN]; - char tgt_buf[MAX_SEPOL_LEN]; - char cls_buf[MAX_SEPOL_LEN]; - - char __maybe_unused - operation[MAX_SEPOL_LEN]; // it is always ioctl now! - char perm_set[MAX_SEPOL_LEN]; - - char *s, *t, *c; - if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(operation, sepol4, - sizeof(operation)) < 0) { - pr_err("sepol: copy operation failed.\n"); - goto exit; - } - if (strncpy_from_user(perm_set, sepol5, sizeof(perm_set)) < - 0) { - pr_err("sepol: copy perm_set failed.\n"); - goto exit; - } - - bool success = false; - if (subcmd == 1) { - success = ksu_allowxperm(db, s, t, c, perm_set); - } else if (subcmd == 2) { - success = ksu_auditallowxperm(db, s, t, c, perm_set); - } else if (subcmd == 3) { - success = ksu_dontauditxperm(db, s, t, c, perm_set); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - ret = success ? 0 : -1; - } else if (cmd == CMD_TYPE_STATE) { - char src[MAX_SEPOL_LEN]; - - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - - bool success = false; - if (subcmd == 1) { - success = ksu_permissive(db, src); - } else if (subcmd == 2) { - success = ksu_enforce(db, src); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - if (success) - ret = 0; - - } else if (cmd == CMD_TYPE || cmd == CMD_TYPE_ATTR) { - char type[MAX_SEPOL_LEN]; - char attr[MAX_SEPOL_LEN]; - - if (strncpy_from_user(type, sepol1, sizeof(type)) < 0) { - pr_err("sepol: copy type failed.\n"); - goto exit; - } - if (strncpy_from_user(attr, sepol2, sizeof(attr)) < 0) { - pr_err("sepol: copy attr failed.\n"); - goto exit; - } - - bool success = false; - if (cmd == CMD_TYPE) { - success = ksu_type(db, type, attr); - } else { - success = ksu_typeattribute(db, type, attr); - } - if (!success) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - - } else if (cmd == CMD_ATTR) { - char attr[MAX_SEPOL_LEN]; - - if (strncpy_from_user(attr, sepol1, sizeof(attr)) < 0) { - pr_err("sepol: copy attr failed.\n"); - goto exit; - } - if (!ksu_attribute(db, attr)) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - - } else if (cmd == CMD_TYPE_TRANSITION) { - char src[MAX_SEPOL_LEN]; - char tgt[MAX_SEPOL_LEN]; - char cls[MAX_SEPOL_LEN]; - char default_type[MAX_SEPOL_LEN]; - char object[MAX_SEPOL_LEN]; - - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(default_type, sepol4, - sizeof(default_type)) < 0) { - pr_err("sepol: copy default_type failed.\n"); - goto exit; - } - char *real_object; - if (sepol5 == NULL) { - real_object = NULL; - } else { - if (strncpy_from_user(object, sepol5, - sizeof(object)) < 0) { - pr_err("sepol: copy object failed.\n"); - goto exit; - } - real_object = object; - } - - bool success = ksu_type_transition(db, src, tgt, cls, - default_type, real_object); - if (success) - ret = 0; - - } else if (cmd == CMD_TYPE_CHANGE) { - char src[MAX_SEPOL_LEN]; - char tgt[MAX_SEPOL_LEN]; - char cls[MAX_SEPOL_LEN]; - char default_type[MAX_SEPOL_LEN]; - - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { - pr_err("sepol: copy src failed.\n"); - goto exit; - } - if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { - pr_err("sepol: copy tgt failed.\n"); - goto exit; - } - if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { - pr_err("sepol: copy cls failed.\n"); - goto exit; - } - if (strncpy_from_user(default_type, sepol4, - sizeof(default_type)) < 0) { - pr_err("sepol: copy default_type failed.\n"); - goto exit; - } - bool success = false; - if (subcmd == 1) { - success = ksu_type_change(db, src, tgt, cls, - default_type); - } else if (subcmd == 2) { - success = ksu_type_member(db, src, tgt, cls, - default_type); - } else { - pr_err("sepol: unknown subcmd: %d\n", subcmd); - } - if (success) - ret = 0; - } else if (cmd == CMD_GENFSCON) { - char name[MAX_SEPOL_LEN]; - char path[MAX_SEPOL_LEN]; - char context[MAX_SEPOL_LEN]; - if (strncpy_from_user(name, sepol1, sizeof(name)) < 0) { - pr_err("sepol: copy name failed.\n"); - goto exit; - } - if (strncpy_from_user(path, sepol2, sizeof(path)) < 0) { - pr_err("sepol: copy path failed.\n"); - goto exit; - } - if (strncpy_from_user(context, sepol3, sizeof(context)) < - 0) { - pr_err("sepol: copy context failed.\n"); - goto exit; - } - - if (!ksu_genfscon(db, name, path, context)) { - pr_err("sepol: %d failed.\n", cmd); - goto exit; - } - ret = 0; - } else { - pr_err("sepol: unknown cmd: %d\n", cmd); - } - -exit: - rcu_read_unlock(); - - // only allow and xallow needs to reset avc cache, but we cannot do that because - // we are in atomic context. so we just reset it every time. - reset_avc_cache(); - - return ret; -} diff --git a/drivers/staging/kernelsu/selinux/selinux.c b/drivers/staging/kernelsu/selinux/selinux.c deleted file mode 100644 index e171e0109d29..000000000000 --- a/drivers/staging/kernelsu/selinux/selinux.c +++ /dev/null @@ -1,230 +0,0 @@ -#include "selinux.h" -#include "objsec.h" -#include "linux/version.h" -#include "../klog.h" // IWYU pragma: keep -#ifndef KSU_COMPAT_USE_SELINUX_STATE -#include "avc.h" -#endif - -#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; - struct task_security_struct *tsec; - u32 sid; - int error; - - cred = (struct cred *)__task_cred(current); - - tsec = cred->security; - if (!tsec) { - pr_err("tsec == NULL!\n"); - return -1; - } - - error = security_secctx_to_secid(domain, strlen(domain), &sid); - if (error) { - pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", - domain, sid, error); - } - if (!error) { - tsec->sid = sid; - tsec->create_sid = 0; - tsec->keycreate_sid = 0; - tsec->sockcreate_sid = 0; - } - return error; -} - -void ksu_setup_selinux(const char *domain) -{ - if (transive_to_domain(domain)) { - pr_err("transive domain failed.\n"); - return; - } - - /* we didn't need this now, we have change selinux rules when boot! -if (!is_domain_permissive) { - if (set_domain_permissive() == 0) { - is_domain_permissive = true; - } -}*/ -} - -void ksu_setenforce(bool enforce) -{ -#ifdef CONFIG_SECURITY_SELINUX_DEVELOP -#ifdef KSU_COMPAT_USE_SELINUX_STATE - selinux_state.enforcing = enforce; -#else - selinux_enforcing = enforce; -#endif -#endif -} - -bool ksu_getenforce() -{ -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -#ifdef KSU_COMPAT_USE_SELINUX_STATE - if (selinux_state.disabled) { -#else - if (selinux_disabled) { -#endif - return false; - } -#endif - -#ifdef CONFIG_SECURITY_SELINUX_DEVELOP -#ifdef KSU_COMPAT_USE_SELINUX_STATE - return selinux_state.enforcing; -#else - return selinux_enforcing; -#endif -#else - return true; -#endif -} - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \ - !defined(KSU_COMPAT_HAS_CURRENT_SID) -/* - * get the subjective security ID of the current task - */ -static inline u32 current_sid(void) -{ - const struct task_security_struct *tsec = current_security(); - - return tsec->sid; -} -#endif - -bool ksu_is_ksu_domain() -{ - char *domain; - u32 seclen; - bool result; - int err = security_secid_to_secctx(current_sid(), &domain, &seclen); - if (err) { - return false; - } - result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0; - security_release_secctx(domain, seclen); - return result; -} - -bool ksu_is_zygote(void *sec) -{ - struct task_security_struct *tsec = (struct task_security_struct *)sec; - if (!tsec) { - return false; - } - char *domain; - u32 seclen; - bool result; - int err = security_secid_to_secctx(tsec->sid, &domain, &seclen); - if (err) { - return false; - } - result = strncmp("u:r:zygote:s0", domain, seclen) == 0; - security_release_secctx(domain, seclen); - 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() -{ - u32 devpts_sid = 0; - int err = security_secctx_to_secid(DEVPTS_DOMAIN, strlen(DEVPTS_DOMAIN), - &devpts_sid); - if (err) { - pr_info("get devpts sid err %d\n", err); - } - return devpts_sid; -} diff --git a/drivers/staging/kernelsu/selinux/selinux.h b/drivers/staging/kernelsu/selinux/selinux.h deleted file mode 100644 index d0dfdf9c935b..000000000000 --- a/drivers/staging/kernelsu/selinux/selinux.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __KSU_H_SELINUX -#define __KSU_H_SELINUX - -#include "linux/types.h" -#include "linux/version.h" - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE) -#define KSU_COMPAT_USE_SELINUX_STATE -#endif - -void ksu_setup_selinux(const char *); - -void ksu_setenforce(bool); - -bool ksu_getenforce(); - -bool ksu_is_ksu_domain(); - -bool ksu_is_zygote(void *cred); - -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(); - -#endif diff --git a/drivers/staging/kernelsu/selinux/sepolicy.c b/drivers/staging/kernelsu/selinux/sepolicy.c deleted file mode 100644 index acdc45ad81f7..000000000000 --- a/drivers/staging/kernelsu/selinux/sepolicy.c +++ /dev/null @@ -1,1070 +0,0 @@ -#include -#include -#include -#include - -#include "sepolicy.h" -#include "../klog.h" // IWYU pragma: keep -#include "ss/symtab.h" -#include "../kernel_compat.h" // Add check Huawei Device - -#define KSU_SUPPORT_ADD_TYPE - -////////////////////////////////////////////////////// -// Declaration -////////////////////////////////////////////////////// - -static struct avtab_node *get_avtab_node(struct policydb *db, - struct avtab_key *key, - struct avtab_extended_perms *xperms); - -static bool add_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *p, int effect, bool invert); - -static void add_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - struct perm_datum *perm, int effect, bool invert); - -static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - uint16_t low, uint16_t high, int effect, - bool invert); -static bool add_xperm_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *range, int effect, - bool invert); - -static bool add_type_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *d, int effect); - -static bool add_filename_trans(struct policydb *db, const char *s, - const char *t, const char *c, const char *d, - const char *o); - -static bool add_genfscon(struct policydb *db, const char *fs_name, - const char *path, const char *context); - -static bool add_type(struct policydb *db, const char *type_name, bool attr); - -static bool set_type_state(struct policydb *db, const char *type_name, - bool permissive); - -static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, - struct type_datum *attr); - -static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr); - -////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////// - -// Invert is adding rules for auditdeny; in other cases, invert is removing -// rules -#define strip_av(effect, invert) ((effect == AVTAB_AUDITDENY) == !invert) - -#define ksu_hash_for_each(node_ptr, n_slot, cur) \ - int i; \ - for (i = 0; i < n_slot; ++i) \ - for (cur = node_ptr[i]; cur; cur = cur->next) - -// htable is a struct instead of pointer above 5.8.0: -// https://elixir.bootlin.com/linux/v5.8-rc1/source/security/selinux/ss/symtab.h -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -#define ksu_hashtab_for_each(htab, cur) \ - ksu_hash_for_each(htab.htable, htab.size, cur) -#else -#define ksu_hashtab_for_each(htab, cur) \ - ksu_hash_for_each(htab->htable, htab->size, cur) -#endif - -// symtab_search is introduced on 5.9.0: -// https://elixir.bootlin.com/linux/v5.9-rc1/source/security/selinux/ss/symtab.h -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) -#define symtab_search(s, name) hashtab_search((s)->table, name) -#define symtab_insert(s, name, datum) hashtab_insert((s)->table, name, datum) -#endif - -#define avtab_for_each(avtab, cur) \ - ksu_hash_for_each(avtab.htable, avtab.nslot, cur); - -static struct avtab_node *get_avtab_node(struct policydb *db, - struct avtab_key *key, - struct avtab_extended_perms *xperms) -{ - struct avtab_node *node; - - /* AVTAB_XPERMS entries are not necessarily unique */ - if (key->specified & AVTAB_XPERMS) { - bool match = false; - node = avtab_search_node(&db->te_avtab, key); - while (node) { - if ((node->datum.u.xperms->specified == - xperms->specified) && - (node->datum.u.xperms->driver == xperms->driver)) { - match = true; - break; - } - node = avtab_search_node_next(node, key->specified); - } - if (!match) - node = NULL; - } else { - node = avtab_search_node(&db->te_avtab, key); - } - - if (!node) { - struct avtab_datum avdatum = {}; - /* - * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for - * others. Initialize the data accordingly. - */ - if (key->specified & AVTAB_XPERMS) { - avdatum.u.xperms = xperms; - } else { - avdatum.u.data = - key->specified == AVTAB_AUDITDENY ? ~0U : 0U; - } - /* this is used to get the node - insertion is actually unique */ - node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum); - - int grow_size = sizeof(struct avtab_key); - grow_size += sizeof(struct avtab_datum); - if (key->specified & AVTAB_XPERMS) { - grow_size += sizeof(u8); - grow_size += sizeof(u8); - grow_size += sizeof(u32) * - ARRAY_SIZE(avdatum.u.xperms->perms.p); - } - db->len += grow_size; - } - - return node; -} - -static bool add_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *p, int effect, bool invert) -{ - struct type_datum *src = NULL, *tgt = NULL; - struct class_datum *cls = NULL; - struct perm_datum *perm = NULL; - - if (s) { - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - } - - if (t) { - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - } - - if (c) { - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - } - - if (p) { - if (c == NULL) { - pr_info("No class is specified, cannot add perm [%s] \n", - p); - return false; - } - - perm = symtab_search(&cls->permissions, p); - if (perm == NULL && cls->comdatum != NULL) { - perm = symtab_search(&cls->comdatum->permissions, p); - } - if (perm == NULL) { - pr_info("perm %s does not exist in class %s\n", p, c); - return false; - } - } - add_rule_raw(db, src, tgt, cls, perm, effect, invert); - return true; -} - -static void add_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - struct perm_datum *perm, int effect, bool invert) -{ - if (src == NULL) { - struct hashtab_node *node; - if (strip_av(effect, invert)) { - ksu_hashtab_for_each(db->p_types.table, node) - { - add_rule_raw(db, - (struct type_datum *)node->datum, - tgt, cls, perm, effect, invert); - }; - } else { - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_rule_raw(db, type, tgt, cls, perm, - effect, invert); - } - }; - } - } else if (tgt == NULL) { - struct hashtab_node *node; - if (strip_av(effect, invert)) { - ksu_hashtab_for_each(db->p_types.table, node) - { - add_rule_raw(db, src, - (struct type_datum *)node->datum, - cls, perm, effect, invert); - }; - } else { - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_rule_raw(db, src, type, cls, perm, - effect, invert); - } - }; - } - } else if (cls == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_classes.table, node) - { - add_rule_raw(db, src, tgt, - (struct class_datum *)node->datum, perm, - effect, invert); - } - } else { - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; - - struct avtab_node *node = get_avtab_node(db, &key, NULL); - if (invert) { - if (perm) - node->datum.u.data &= - ~(1U << (perm->value - 1)); - else - node->datum.u.data = 0U; - } else { - if (perm) - node->datum.u.data |= 1U << (perm->value - 1); - else - node->datum.u.data = ~0U; - } - } -} - -#define ioctl_driver(x) (x >> 8 & 0xFF) -#define ioctl_func(x) (x & 0xFF) - -#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f))) -#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f))) -#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f))) - -static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, - struct type_datum *tgt, struct class_datum *cls, - uint16_t low, uint16_t high, int effect, - bool invert) -{ - if (src == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_xperm_rule_raw(db, type, tgt, cls, low, - high, effect, invert); - } - }; - } else if (tgt == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - struct type_datum *type = - (struct type_datum *)(node->datum); - if (type->attribute) { - add_xperm_rule_raw(db, src, type, cls, low, - high, effect, invert); - } - }; - } else if (cls == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_classes.table, node) - { - add_xperm_rule_raw(db, src, tgt, - (struct class_datum *)(node->datum), - low, high, effect, invert); - }; - } else { - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; - - struct avtab_datum *datum; - struct avtab_node *node; - struct avtab_extended_perms xperms; - - memset(&xperms, 0, sizeof(xperms)); - if (ioctl_driver(low) != ioctl_driver(high)) { - xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; - xperms.driver = 0; - } else { - xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; - xperms.driver = ioctl_driver(low); - } - int i; - if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { - for (i = ioctl_driver(low); i <= ioctl_driver(high); - ++i) { - if (invert) - xperm_clear(i, xperms.perms.p); - else - xperm_set(i, xperms.perms.p); - } - } else { - for (i = ioctl_func(low); i <= ioctl_func(high); ++i) { - if (invert) - xperm_clear(i, xperms.perms.p); - else - xperm_set(i, xperms.perms.p); - } - } - - node = get_avtab_node(db, &key, &xperms); - if (!node) { - pr_warn("add_xperm_rule_raw cannot found node!\n"); - return; - } - datum = &node->datum; - - if (datum->u.xperms == NULL) { - datum->u.xperms = - (struct avtab_extended_perms *)(kmalloc( - sizeof(xperms), GFP_KERNEL)); - if (!datum->u.xperms) { - pr_err("alloc xperms failed\n"); - return; - } - memcpy(datum->u.xperms, &xperms, sizeof(xperms)); - } - } -} - -static bool add_xperm_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *range, int effect, - bool invert) -{ - struct type_datum *src = NULL, *tgt = NULL; - struct class_datum *cls = NULL; - - if (s) { - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - } - - if (t) { - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - } - - if (c) { - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - } - - u16 low, high; - - if (range) { - if (strchr(range, '-')) { - sscanf(range, "%hx-%hx", &low, &high); - } else { - sscanf(range, "%hx", &low); - high = low; - } - } else { - low = 0; - high = 0xFFFF; - } - - add_xperm_rule_raw(db, src, tgt, cls, low, high, effect, invert); - return true; -} - -static bool add_type_rule(struct policydb *db, const char *s, const char *t, - const char *c, const char *d, int effect) -{ - struct type_datum *src, *tgt, *def; - struct class_datum *cls; - - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_info("source type %s does not exist\n", s); - return false; - } - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_info("target type %s does not exist\n", t); - return false; - } - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_info("class %s does not exist\n", c); - return false; - } - def = symtab_search(&db->p_types, d); - if (def == NULL) { - pr_info("default type %s does not exist\n", d); - return false; - } - - struct avtab_key key; - key.source_type = src->value; - key.target_type = tgt->value; - key.target_class = cls->value; - key.specified = effect; - - struct avtab_node *node = get_avtab_node(db, &key, NULL); - node->datum.u.data = def->value; - - return true; -} - -// 5.9.0 : static inline int hashtab_insert(struct hashtab *h, void *key, void -// *datum, struct hashtab_key_params key_params) 5.8.0: int -// hashtab_insert(struct hashtab *h, void *k, void *d); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) -static u32 filenametr_hash(const void *k) -{ - const struct filename_trans_key *ft = k; - unsigned long hash; - unsigned int byte_num; - unsigned char focus; - - hash = ft->ttype ^ ft->tclass; - - byte_num = 0; - while ((focus = ft->name[byte_num++])) - hash = partial_name_hash(focus, hash); - return hash; -} - -static int filenametr_cmp(const void *k1, const void *k2) -{ - const struct filename_trans_key *ft1 = k1; - const struct filename_trans_key *ft2 = k2; - int v; - - v = ft1->ttype - ft2->ttype; - if (v) - return v; - - v = ft1->tclass - ft2->tclass; - if (v) - return v; - - return strcmp(ft1->name, ft2->name); -} - -static const struct hashtab_key_params filenametr_key_params = { - .hash = filenametr_hash, - .cmp = filenametr_cmp, -}; -#endif - -static bool add_filename_trans(struct policydb *db, const char *s, - const char *t, const char *c, const char *d, - const char *o) -{ - struct type_datum *src, *tgt, *def; - struct class_datum *cls; - - src = symtab_search(&db->p_types, s); - if (src == NULL) { - pr_warn("source type %s does not exist\n", s); - return false; - } - tgt = symtab_search(&db->p_types, t); - if (tgt == NULL) { - pr_warn("target type %s does not exist\n", t); - return false; - } - cls = symtab_search(&db->p_classes, c); - if (cls == NULL) { - pr_warn("class %s does not exist\n", c); - return false; - } - def = symtab_search(&db->p_types, d); - if (def == NULL) { - pr_warn("default type %s does not exist\n", d); - return false; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) - struct filename_trans_key key; - key.ttype = tgt->value; - key.tclass = cls->value; - key.name = (char *)o; - - struct filename_trans_datum *last = NULL; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - struct filename_trans_datum *trans = - policydb_filenametr_search(db, &key); -#else - struct filename_trans_datum *trans = - hashtab_search(&db->filename_trans, &key); -#endif - while (trans) { - if (ebitmap_get_bit(&trans->stypes, src->value - 1)) { - // Duplicate, overwrite existing data and return - trans->otype = def->value; - return true; - } - if (trans->otype == def->value) - break; - last = trans; - trans = trans->next; - } - - if (trans == NULL) { - trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), - 1, GFP_ATOMIC); - struct filename_trans_key *new_key = - (struct filename_trans_key *)kmalloc(sizeof(*new_key), - GFP_ATOMIC); - *new_key = key; - new_key->name = kstrdup(key.name, GFP_ATOMIC); - trans->next = last; - trans->otype = def->value; - hashtab_insert(&db->filename_trans, new_key, trans, - filenametr_key_params); - } - - db->compat_filename_trans_count++; - return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0; -#else // < 5.7.0, has no filename_trans_key, but struct filename_trans - - struct filename_trans key; - key.ttype = tgt->value; - key.tclass = cls->value; - key.name = (char *)o; - - struct filename_trans_datum *trans = - hashtab_search(db->filename_trans, &key); - - if (trans == NULL) { - trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans), - 1, GFP_ATOMIC); - if (!trans) { - pr_err("add_filename_trans: Failed to alloc datum\n"); - return false; - } - struct filename_trans *new_key = - (struct filename_trans *)kmalloc(sizeof(*new_key), - GFP_ATOMIC); - if (!new_key) { - pr_err("add_filename_trans: Failed to alloc new_key\n"); - return false; - } - *new_key = key; - new_key->name = kstrdup(key.name, GFP_ATOMIC); - trans->otype = def->value; - hashtab_insert(db->filename_trans, new_key, trans); - } - - return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) == - 0; -#endif -} - -static bool add_genfscon(struct policydb *db, const char *fs_name, - const char *path, const char *context) -{ - return false; -} - -static void *ksu_realloc(void *old, size_t new_size, size_t old_size) -{ - // we can't use krealloc, because it may be read-only - void *new = kzalloc(new_size, GFP_ATOMIC); - if (!new) { - return NULL; - } - if (old_size) { - memcpy(new, old, old_size); - } - // we can't use kfree, because it may be read-only - // there maybe some leaks, maybe we can check ptr_write, but it's not a big deal - // kfree(old); - return new; -} - -static bool add_type(struct policydb *db, const char *type_name, bool attr) -{ -#ifdef KSU_SUPPORT_ADD_TYPE - struct type_datum *type = symtab_search(&db->p_types, type_name); - if (type) { - pr_warn("Type %s already exists\n", type_name); - return true; - } - - u32 value = ++db->p_types.nprim; - type = (struct type_datum *)kzalloc(sizeof(struct type_datum), - GFP_ATOMIC); - if (!type) { - pr_err("add_type: alloc type_datum failed.\n"); - return false; - } - - type->primary = 1; - type->value = value; - type->attribute = attr; - - char *key = kstrdup(type_name, GFP_ATOMIC); - if (!key) { - pr_err("add_type: alloc key failed.\n"); - return false; - } - - if (symtab_insert(&db->p_types, key, type)) { - pr_err("add_type: insert symtab failed.\n"); - return false; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) - struct ebitmap *new_type_attr_map_array = - ksu_realloc(db->type_attr_map_array, - value * sizeof(struct ebitmap), - (value - 1) * sizeof(struct ebitmap)); - - if (!new_type_attr_map_array) { - pr_err("add_type: alloc type_attr_map_array failed\n"); - return false; - } - - struct type_datum **new_type_val_to_struct = - ksu_realloc(db->type_val_to_struct, - sizeof(*db->type_val_to_struct) * value, - sizeof(*db->type_val_to_struct) * (value - 1)); - - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } - - char **new_val_to_name_types = - ksu_realloc(db->sym_val_to_name[SYM_TYPES], - sizeof(char *) * value, - sizeof(char *) * (value - 1)); - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } - - db->type_attr_map_array = new_type_attr_map_array; - ebitmap_init(&db->type_attr_map_array[value - 1]); - ebitmap_set_bit(&db->type_attr_map_array[value - 1], value - 1, 1); - - db->type_val_to_struct = new_type_val_to_struct; - db->type_val_to_struct[value - 1] = type; - - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - db->sym_val_to_name[SYM_TYPES][value - 1] = key; - - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } - - return true; -#elif defined(CONFIG_IS_HW_HISI) - /* - * Huawei use type_attr_map and type_val_to_struct. - * And use ebitmap not flex_array. - */ - size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim; - struct ebitmap *new_type_attr_map = - (krealloc(db->type_attr_map, new_size, GFP_ATOMIC)); - - struct type_datum **new_type_val_to_struct = - krealloc(db->type_val_to_struct, - sizeof(*db->type_val_to_struct) * db->p_types.nprim, - GFP_ATOMIC); - - if (!new_type_attr_map) { - pr_err("add_type: alloc type_attr_map failed\n"); - return false; - } - - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } - - char **new_val_to_name_types = - krealloc(db->sym_val_to_name[SYM_TYPES], - sizeof(char *) * db->symtab[SYM_TYPES].nprim, - GFP_KERNEL); - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } - - db->type_attr_map = new_type_attr_map; - ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO); - ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1); - - db->type_val_to_struct = new_type_val_to_struct; - db->type_val_to_struct[value - 1] = type; - - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - db->sym_val_to_name[SYM_TYPES][value - 1] = key; - - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } - - return true; -#else - // flex_array is not extensible, we need to create a new bigger one instead - struct flex_array *new_type_attr_map_array = - flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO); - - struct flex_array *new_type_val_to_struct = - flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO); - - struct flex_array *new_val_to_name_types = - flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim, - GFP_ATOMIC | __GFP_ZERO); - - if (!new_type_attr_map_array) { - pr_err("add_type: alloc type_attr_map_array failed\n"); - return false; - } - - if (!new_type_val_to_struct) { - pr_err("add_type: alloc type_val_to_struct failed\n"); - return false; - } - - if (!new_val_to_name_types) { - pr_err("add_type: alloc val_to_name failed\n"); - return false; - } - - // preallocate so we don't have to worry about the put ever failing - if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc type_attr_map_array failed\n"); - return false; - } - - if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc type_val_to_struct_array failed\n"); - return false; - } - - if (flex_array_prealloc(new_val_to_name_types, 0, - db->symtab[SYM_TYPES].nprim, - GFP_ATOMIC | __GFP_ZERO)) { - pr_err("add_type: prealloc val_to_name_types failed\n"); - return false; - } - - int j; - void *old_elem; - // copy the old data or pointers to new flex arrays - for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) { - old_elem = flex_array_get(db->type_attr_map_array, j); - if (old_elem) - flex_array_put(new_type_attr_map_array, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } - - for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) { - old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j); - if (old_elem) - flex_array_put_ptr(new_type_val_to_struct, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } - - for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) { - old_elem = - flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j); - if (old_elem) - flex_array_put_ptr(new_val_to_name_types, j, old_elem, - GFP_ATOMIC | __GFP_ZERO); - } - - // store the pointer of old flex arrays first, when assigning new ones we - // should free it - struct flex_array *old_fa; - - old_fa = db->type_attr_map_array; - db->type_attr_map_array = new_type_attr_map_array; - if (old_fa) { - flex_array_free(old_fa); - } - - ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1)); - ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1), - value - 1, 1); - - old_fa = db->type_val_to_struct_array; - db->type_val_to_struct_array = new_type_val_to_struct; - if (old_fa) { - flex_array_free(old_fa); - } - flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type, - GFP_ATOMIC | __GFP_ZERO); - - old_fa = db->sym_val_to_name[SYM_TYPES]; - db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types; - if (old_fa) { - flex_array_free(old_fa); - } - flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key, - GFP_ATOMIC | __GFP_ZERO); - - int i; - for (i = 0; i < db->p_roles.nprim; ++i) { - ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1, - 1); - } - return true; -#endif - -#else - return false; -#endif -} - -static bool set_type_state(struct policydb *db, const char *type_name, - bool permissive) -{ - struct type_datum *type; - if (type_name == NULL) { - struct hashtab_node *node; - ksu_hashtab_for_each(db->p_types.table, node) - { - type = (struct type_datum *)(node->datum); - if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) - pr_info("Could not set bit in permissive map\n"); - }; - } else { - type = (struct type_datum *)symtab_search(&db->p_types, - type_name); - if (type == NULL) { - pr_info("type %s does not exist\n", type_name); - return false; - } - if (ebitmap_set_bit(&db->permissive_map, type->value, - permissive)) { - pr_info("Could not set bit in permissive map\n"); - return false; - } - } - return true; -} - -static void add_typeattribute_raw(struct policydb *db, struct type_datum *type, - struct type_datum *attr) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) - struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1]; -#elif defined(CONFIG_IS_HW_HISI) - /* - * HISI_SELINUX_EBITMAP_RO is Huawei's unique features. - */ - struct ebitmap *sattr = &db->type_attr_map[type->value - 1], - HISI_SELINUX_EBITMAP_RO; -#else - struct ebitmap *sattr = - flex_array_get(db->type_attr_map_array, type->value - 1); -#endif - ebitmap_set_bit(sattr, attr->value - 1, 1); - - struct hashtab_node *node; - struct constraint_node *n; - struct constraint_expr *e; - ksu_hashtab_for_each(db->p_classes.table, node) - { - struct class_datum *cls = (struct class_datum *)(node->datum); - for (n = cls->constraints; n; n = n->next) { - for (e = n->expr; e; e = e->next) { - if (e->expr_type == CEXPR_NAMES && - ebitmap_get_bit(&e->type_names->types, - attr->value - 1)) { - ebitmap_set_bit(&e->names, - type->value - 1, 1); - } - } - } - }; -} - -static bool add_typeattribute(struct policydb *db, const char *type, - const char *attr) -{ - struct type_datum *type_d = symtab_search(&db->p_types, type); - if (type_d == NULL) { - pr_info("type %s does not exist\n", type); - return false; - } else if (type_d->attribute) { - pr_info("type %s is an attribute\n", attr); - return false; - } - - struct type_datum *attr_d = symtab_search(&db->p_types, attr); - if (attr_d == NULL) { - pr_info("attribute %s does not exist\n", type); - return false; - } else if (!attr_d->attribute) { - pr_info("type %s is not an attribute \n", attr); - return false; - } - - add_typeattribute_raw(db, type_d, attr_d); - return true; -} - -////////////////////////////////////////////////////////////////////////// - -// Operation on types -bool ksu_type(struct policydb *db, const char *name, const char *attr) -{ - return add_type(db, name, false) && add_typeattribute(db, name, attr); -} - -bool ksu_attribute(struct policydb *db, const char *name) -{ - return add_type(db, name, true); -} - -bool ksu_permissive(struct policydb *db, const char *type) -{ - return set_type_state(db, type, true); -} - -bool ksu_enforce(struct policydb *db, const char *type) -{ - return set_type_state(db, type, false); -} - -bool ksu_typeattribute(struct policydb *db, const char *type, const char *attr) -{ - return add_typeattribute(db, type, attr); -} - -bool ksu_exists(struct policydb *db, const char *type) -{ - return symtab_search(&db->p_types, type) != NULL; -} - -// Access vector rules -bool ksu_allow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) -{ - return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, false); -} - -bool ksu_deny(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) -{ - return add_rule(db, src, tgt, cls, perm, AVTAB_ALLOWED, true); -} - -bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) -{ - return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITALLOW, false); -} -bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm) -{ - return add_rule(db, src, tgt, cls, perm, AVTAB_AUDITDENY, true); -} - -// Extended permissions access vector rules -bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) -{ - return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_ALLOWED, - false); -} - -bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) -{ - return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_AUDITALLOW, - false); -} - -bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range) -{ - return add_xperm_rule(db, src, tgt, cls, range, AVTAB_XPERMS_DONTAUDIT, - false); -} - -// Type rules -bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def, const char *obj) -{ - if (obj) { - return add_filename_trans(db, src, tgt, cls, def, obj); - } else { - return add_type_rule(db, src, tgt, cls, def, AVTAB_TRANSITION); - } -} - -bool ksu_type_change(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def) -{ - return add_type_rule(db, src, tgt, cls, def, AVTAB_CHANGE); -} - -bool ksu_type_member(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def) -{ - return add_type_rule(db, src, tgt, cls, def, AVTAB_MEMBER); -} - -// File system labeling -bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path, - const char *ctx) -{ - return add_genfscon(db, fs_name, path, ctx); -} diff --git a/drivers/staging/kernelsu/selinux/sepolicy.h b/drivers/staging/kernelsu/selinux/sepolicy.h deleted file mode 100644 index 675d1499e46d..000000000000 --- a/drivers/staging/kernelsu/selinux/sepolicy.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __KSU_H_SEPOLICY -#define __KSU_H_SEPOLICY - -#include - -#include "ss/policydb.h" - -// Operation on types -bool ksu_type(struct policydb *db, const char *name, const char *attr); -bool ksu_attribute(struct policydb *db, const char *name); -bool ksu_permissive(struct policydb *db, const char *type); -bool ksu_enforce(struct policydb *db, const char *type); -bool ksu_typeattribute(struct policydb *db, const char *type, const char *attr); -bool ksu_exists(struct policydb *db, const char *type); - -// Access vector rules -bool ksu_allow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); -bool ksu_deny(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); -bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); -bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *perm); - -// Extended permissions access vector rules -bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range); -bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range); -bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *range); - -// Type rules -bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def, const char *obj); -bool ksu_type_change(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def); -bool ksu_type_member(struct policydb *db, const char *src, const char *tgt, - const char *cls, const char *def); - -// File system labeling -bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path, - const char *ctx); - -#endif diff --git a/drivers/staging/kernelsu/sucompat.c b/drivers/staging/kernelsu/sucompat.c deleted file mode 100644 index 3140f00fc57d..000000000000 --- a/drivers/staging/kernelsu/sucompat.c +++ /dev/null @@ -1,409 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -#include -#else -#include -#endif -#ifdef CONFIG_KSU_SUSFS_SUS_SU -#include -#endif - -#include "objsec.h" -#include "allowlist.h" -#include "arch.h" -#include "klog.h" // IWYU pragma: keep -#include "ksud.h" -#include "kernel_compat.h" - -#define SU_PATH "/system/bin/su" -#define SH_PATH "/system/bin/sh" - -#ifndef CONFIG_KSU_KPROBES_HOOK -static bool ksu_sucompat_non_kp __read_mostly = true; -#endif - -extern void ksu_escape_to_root(); - -static const char sh_path[] = "/system/bin/sh"; -static const char ksud_path[] = KSUD_PATH; -static const char su[] = SU_PATH; - -static inline void __user *userspace_stack_buffer(const void *d, size_t len) -{ - /* To avoid having to mmap a page in userspace, just write below the stack - * pointer. */ - char __user *p = (void __user *)current_user_stack_pointer() - len; - - return copy_to_user(p, d, len) ? NULL : p; -} - -static inline char __user *sh_user_path(void) -{ - return userspace_stack_buffer(sh_path, sizeof(sh_path)); -} - -static inline char __user *ksud_user_path(void) -{ - return userspace_stack_buffer(ksud_path, sizeof(ksud_path)); -} - -int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *__unused_flags) -{ -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_non_kp) { - return 0; - } -#endif - -#ifndef CONFIG_KSU_SUSFS_SUS_SU - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } -#endif - -#ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su)] = {0}; -#else - char path[sizeof(su) + 1]; - memset(path, 0, sizeof(path)); -#endif - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - - if (unlikely(!memcmp(path, su, sizeof(su)))) { - pr_info("faccessat su->sh!\n"); - *filename_user = sh_user_path(); - } - - 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) { - struct filename *name = getname_flags(*filename_user, getname_statx_lookup_flags(*flags), NULL); - - if (unlikely(IS_ERR(name) || name->name == NULL)) { - 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) -{ -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_non_kp){ - return 0; - } -#endif - -#ifndef CONFIG_KSU_SUSFS_SUS_SU - if (!ksu_is_allow_uid(current_uid().val)) { - return 0; - } -#endif - - if (unlikely(!filename_user)) { - return 0; - } - -#ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su)] = {0}; -#else - char path[sizeof(su) + 1]; - memset(path, 0, sizeof(path)); -#endif -// Remove this later!! we use syscall hook, so this will never happen!!!!! -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0 - // it becomes a `struct filename *` after 5.18 - // https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216 - const char sh[] = SH_PATH; - struct filename *filename = *((struct filename **)filename_user); - if (IS_ERR(filename)) { - return 0; - } - if (likely(memcmp(filename->name, su, sizeof(su)))) - return 0; - pr_info("vfs_statx su->sh!\n"); - memcpy((void *)filename->name, sh, sizeof(sh)); -#else - ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - - if (unlikely(!memcmp(path, su, sizeof(su)))) { - pr_info("newfstatat su->sh!\n"); - *filename_user = sh_user_path(); - } -#endif - - return 0; -} - -// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code -int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags) -{ - struct filename *filename; - -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_non_kp) { - return 0; - } -#endif - - if (unlikely(!filename_ptr)) - return 0; - - filename = *filename_ptr; - if (IS_ERR(filename)) { - return 0; - } - - if (likely(memcmp(filename->name, su, sizeof(su)))) - return 0; - -#ifndef CONFIG_KSU_SUSFS_SUS_SU - if (!ksu_is_allow_uid(current_uid().val)) - return 0; -#endif - - pr_info("do_execveat_common su found\n"); - memcpy((void *)filename->name, ksud_path, sizeof(ksud_path)); - - ksu_escape_to_root(); - - return 0; -} - -int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags) -{ -#ifdef CONFIG_KSU_SUSFS_SUS_SU - char path[sizeof(su)] = {0}; -#else - char path[sizeof(su) + 1]; -#endif - -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_non_kp) { - return 0; - } -#endif - - if (unlikely(!filename_user)) - return 0; - - memset(path, 0, sizeof(path)); - ksu_strncpy_from_user_retry(path, *filename_user, sizeof(path)); - - if (likely(memcmp(path, su, sizeof(su)))) - return 0; - - if (!ksu_is_allow_uid(current_uid().val)) - return 0; - - pr_info("sys_execve su found\n"); - *filename_user = ksud_user_path(); - - ksu_escape_to_root(); - - return 0; -} - -int ksu_handle_devpts(struct inode *inode) -{ -#ifndef CONFIG_KSU_KPROBES_HOOK - if (!ksu_sucompat_non_kp) { - return 0; - } -#endif - - if (!current->mm) { - return 0; - } - - uid_t uid = current_uid().val; - if (uid % 100000 < 10000) { - // not untrusted_app, ignore it - return 0; - } - - if (!ksu_is_allow_uid(uid)) - return 0; - - if (ksu_devpts_sid) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) - struct inode_security_struct *sec = selinux_inode(inode); -#else - struct inode_security_struct *sec = - (struct inode_security_struct *)inode->i_security; -#endif - if (sec) { - sec->sid = ksu_devpts_sid; - } - } - - return 0; -} - -#ifdef CONFIG_KSU_KPROBES_HOOK - -static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *mode = (int *)&PT_REGS_PARM3(real_regs); - - return ksu_handle_faccessat(dfd, filename_user, mode, NULL); -} - -static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs); - - return ksu_handle_stat(dfd, filename_user, flags); -} - -static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM1(real_regs); - - return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, - NULL); -} - -static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct inode *inode; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) - struct file *file = (struct file *)PT_REGS_PARM2(regs); - inode = file->f_path.dentry->d_inode; -#else - inode = (struct inode *)PT_REGS_PARM2(regs); -#endif - - return ksu_handle_devpts(inode); -} - -static struct kprobe *init_kprobe(const char *name, - kprobe_pre_handler_t handler) -{ - struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL); - if (!kp) - return NULL; - kp->symbol_name = name; - kp->pre_handler = handler; - - int ret = register_kprobe(kp); - pr_info("sucompat: register_%s kprobe: %d\n", name, ret); - if (ret) { - kfree(kp); - return NULL; - } - - return kp; -} - -static void destroy_kprobe(struct kprobe **kp_ptr) -{ - struct kprobe *kp = *kp_ptr; - if (!kp) - return; - unregister_kprobe(kp); - synchronize_rcu(); - kfree(kp); - *kp_ptr = NULL; -} - -static struct kprobe *su_kps[4]; -#endif - -// sucompat: permited process can execute 'su' to gain root access. -void ksu_sucompat_init() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); - su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); - su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre); - su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); -#else - ksu_sucompat_non_kp = true; - pr_info("ksu_sucompat_init: hooks enabled: execve/execveat_su, faccessat, stat, devpts\n"); -#endif -} - -void ksu_sucompat_exit() -{ -#ifdef CONFIG_KSU_KPROBES_HOOK - for (int i = 0; i < ARRAY_SIZE(su_kps); i++) { - destroy_kprobe(&su_kps[i]); - } -#else - ksu_sucompat_non_kp = false; - pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat, devpts\n"); -#endif -} - -#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) { - for (int i = 0; i < ARRAY_SIZE(su_kps); i++) { - if (su_kps[i]) { - return true; - } - } - 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 - diff --git a/drivers/staging/kernelsu/throne_tracker.c b/drivers/staging/kernelsu/throne_tracker.c deleted file mode 100644 index bfd337170b02..000000000000 --- a/drivers/staging/kernelsu/throne_tracker.c +++ /dev/null @@ -1,469 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "allowlist.h" -#include "klog.h" // IWYU pragma: keep -#include "ksu.h" -#include "manager.h" -#include "throne_tracker.h" -#include "kernel_compat.h" - -uid_t ksu_manager_uid = KSU_INVALID_UID; - -#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list.tmp" - -struct uid_data { - struct list_head list; - u32 uid; - char package[KSU_MAX_PACKAGE_NAME]; -}; - -static int get_pkg_from_apk_path(char *pkg, const char *path) -{ - int len = strlen(path); - if (len >= KSU_MAX_PACKAGE_NAME || len < 1) - return -1; - - const char *last_slash = NULL; - const char *second_last_slash = NULL; - - int i; - for (i = len - 1; i >= 0; i--) { - if (path[i] == '/') { - if (!last_slash) { - last_slash = &path[i]; - } else { - second_last_slash = &path[i]; - break; - } - } - } - - if (!last_slash || !second_last_slash) - return -1; - - const char *last_hyphen = strchr(second_last_slash, '-'); - if (!last_hyphen || last_hyphen > last_slash) - return -1; - - int pkg_len = last_hyphen - second_last_slash - 1; - if (pkg_len >= KSU_MAX_PACKAGE_NAME || pkg_len <= 0) - return -1; - - // Copying the package name - strncpy(pkg, second_last_slash + 1, pkg_len); - pkg[pkg_len] = '\0'; - - return 0; -} - -static void crown_manager(const char *apk, struct list_head *uid_data) -{ - char pkg[KSU_MAX_PACKAGE_NAME]; - if (get_pkg_from_apk_path(pkg, apk) < 0) { - pr_err("Failed to get package name from apk path: %s\n", apk); - return; - } - - pr_info("manager pkg: %s\n", pkg); - -#ifdef KSU_MANAGER_PACKAGE - // pkg is `/` - if (strncmp(pkg, KSU_MANAGER_PACKAGE, sizeof(KSU_MANAGER_PACKAGE))) { - pr_info("manager package is inconsistent with kernel build: %s\n", - KSU_MANAGER_PACKAGE); - return; - } -#endif - struct list_head *list = (struct list_head *)uid_data; - struct uid_data *np; - - list_for_each_entry (np, list, list) { - if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) { - pr_info("Crowning manager: %s(uid=%d)\n", pkg, np->uid); - ksu_set_manager_uid(np->uid); - break; - } - } -} - -#define DATA_PATH_LEN 384 // 384 is enough for /data/app//base.apk - -struct data_path { - char dirpath[DATA_PATH_LEN]; - int depth; - struct list_head list; -}; - -struct apk_path_hash { - unsigned int hash; - bool exists; - struct list_head list; -}; - -static struct list_head apk_path_hash_list = LIST_HEAD_INIT(apk_path_hash_list); - -struct my_dir_context { - struct dir_context ctx; - struct list_head *data_path_list; - char *parent_dir; - void *private_data; - int depth; - int *stop; -}; -// https://docs.kernel.org/filesystems/porting.html -// filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: callers never looked at specific -E... values anyway. -> iterate_shared() instances require no changes at all, all filldir_t ones in the tree converted. -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) -#define FILLDIR_RETURN_TYPE bool -#define FILLDIR_ACTOR_CONTINUE true -#define FILLDIR_ACTOR_STOP false -#else -#define FILLDIR_RETURN_TYPE int -#define FILLDIR_ACTOR_CONTINUE 0 -#define FILLDIR_ACTOR_STOP -EINVAL -#endif - -FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, - int namelen, loff_t off, u64 ino, - unsigned int d_type) -{ - struct my_dir_context *my_ctx = - container_of(ctx, struct my_dir_context, ctx); - char dirpath[DATA_PATH_LEN]; - - if (!my_ctx) { - pr_err("Invalid context\n"); - return FILLDIR_ACTOR_STOP; - } - if (my_ctx->stop && *my_ctx->stop) { - pr_info("Stop searching\n"); - return FILLDIR_ACTOR_STOP; - } - - if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen)) - return FILLDIR_ACTOR_CONTINUE; // Skip "." and ".." - - if (d_type == DT_DIR && namelen >= 8 && !strncmp(name, "vmdl", 4) && - !strncmp(name + namelen - 4, ".tmp", 4)) { - pr_info("Skipping directory: %.*s\n", namelen, name); - return FILLDIR_ACTOR_CONTINUE; // Skip staging package - } - - if (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir, - namelen, name) >= DATA_PATH_LEN) { - pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen, - name); - return FILLDIR_ACTOR_CONTINUE; - } - - if (d_type == DT_DIR && my_ctx->depth > 0 && - (my_ctx->stop && !*my_ctx->stop)) { - struct data_path *data = kmalloc(sizeof(struct data_path), GFP_ATOMIC); - - if (!data) { - pr_err("Failed to allocate memory for %s\n", dirpath); - return FILLDIR_ACTOR_CONTINUE; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) - strlcpy(data->dirpath, dirpath, DATA_PATH_LEN); -#else - strscpy(data->dirpath, dirpath, DATA_PATH_LEN); -#endif - data->depth = my_ctx->depth - 1; - list_add_tail(&data->list, my_ctx->data_path_list); - } else { - if ((namelen == 8) && (strncmp(name, "base.apk", namelen) == 0)) { - struct apk_path_hash *pos, *n; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) - unsigned int hash = full_name_hash(dirpath, strlen(dirpath)); -#else - unsigned int hash = full_name_hash(NULL, dirpath, strlen(dirpath)); -#endif - list_for_each_entry(pos, &apk_path_hash_list, list) { - if (hash == pos->hash) { - pos->exists = true; - return FILLDIR_ACTOR_CONTINUE; - } - } - - 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) { - crown_manager(dirpath, my_ctx->private_data); - *my_ctx->stop = 1; - - // Manager found, clear APK cache list - list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { - list_del(&pos->list); - kfree(pos); - } - } else { - struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC); - apk_data->hash = hash; - apk_data->exists = true; - list_add_tail(&apk_data->list, &apk_path_hash_list); - } - } - } - - return FILLDIR_ACTOR_CONTINUE; -} - -/* - * small helper to check if lock is held - * false - file is stable - * true - file is being deleted/renamed - * possibly optional - * - */ -bool is_lock_held(const char *path) -{ - struct path kpath; - - // kern_path returns 0 on success - if (kern_path(path, 0, &kpath)) - return true; - - // just being defensive - if (!kpath.dentry) { - path_put(&kpath); - return true; - } - - if (!spin_trylock(&kpath.dentry->d_lock)) { - pr_info("%s: lock held, bail out!\n", __func__); - path_put(&kpath); - return true; - } - // we hold it ourselves here! - - spin_unlock(&kpath.dentry->d_lock); - path_put(&kpath); - return false; -} - -// compat: https://elixir.bootlin.com/linux/v3.9/source/include/linux/fs.h#L771 -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) -#define S_MAGIC_COMPAT(x) ((x)->f_inode->i_sb->s_magic) -#else -#define S_MAGIC_COMPAT(x) ((x)->f_path.dentry->d_inode->i_sb->s_magic) -#endif - -void search_manager(const char *path, int depth, struct list_head *uid_data) -{ - int i, stop = 0; - struct list_head data_path_list; - INIT_LIST_HEAD(&data_path_list); - unsigned long data_app_magic = 0; - - // Initialize APK cache list - struct apk_path_hash *pos, *n; - list_for_each_entry(pos, &apk_path_hash_list, list) { - pos->exists = false; - } - - // First depth - struct data_path data; -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) - strlcpy(data.dirpath, path, DATA_PATH_LEN); -#else - strscpy(data.dirpath, path, DATA_PATH_LEN); -#endif - data.depth = depth; - list_add_tail(&data.list, &data_path_list); - - for (i = depth; i >= 0; i--) { - struct data_path *pos, *n; - - list_for_each_entry_safe(pos, n, &data_path_list, list) { - struct my_dir_context ctx = { .ctx.actor = my_actor, - .data_path_list = &data_path_list, - .parent_dir = pos->dirpath, - .private_data = uid_data, - .depth = pos->depth, - .stop = &stop }; - struct file *file; - - if (!stop) { - file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0); - if (IS_ERR(file)) { - pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file)); - goto skip_iterate; - } - - // grab magic on first folder, which is /data/app - if (!data_app_magic) { - if (S_MAGIC_COMPAT(file)) { - data_app_magic = S_MAGIC_COMPAT(file); - pr_info("%s: dir: %s got magic! 0x%lx\n", __func__, pos->dirpath, data_app_magic); - } else { - filp_close(file, NULL); - goto skip_iterate; - } - } - - if (S_MAGIC_COMPAT(file) != data_app_magic) { - pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n", __func__, pos->dirpath, - S_MAGIC_COMPAT(file), data_app_magic); - filp_close(file, NULL); - goto skip_iterate; - } - - iterate_dir(file, &ctx.ctx); - filp_close(file, NULL); - } -skip_iterate: - list_del(&pos->list); - if (pos != &data) - kfree(pos); - } - } - - // Remove stale cached APK entries - list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) { - if (!pos->exists) { - list_del(&pos->list); - kfree(pos); - } - } -} - -static bool is_uid_exist(uid_t uid, char *package, void *data) -{ - struct list_head *list = (struct list_head *)data; - struct uid_data *np; - - bool exist = false; - list_for_each_entry (np, list, list) { - if (np->uid == uid % 100000 && - strncmp(np->package, package, KSU_MAX_PACKAGE_NAME) == 0) { - exist = true; - break; - } - } - return exist; -} - -void ksu_track_throne() -{ - struct file *fp; - int tries = 0; - - while (tries++ < 10) { - if (!is_lock_held(SYSTEM_PACKAGES_LIST_PATH)) { - fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); - if (!IS_ERR(fp)) - break; - } - - pr_info("%s: waiting for %s\n", __func__, SYSTEM_PACKAGES_LIST_PATH); - msleep(100); // migth as well add a delay - }; - - if (IS_ERR(fp)) { - pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp)); - return; - } else - pr_info("%s: %s found!\n", __func__, SYSTEM_PACKAGES_LIST_PATH); - - struct list_head uid_list; - INIT_LIST_HEAD(&uid_list); - - char chr = 0; - loff_t pos = 0; - loff_t line_start = 0; - char buf[KSU_MAX_PACKAGE_NAME]; - for (;;) { - ssize_t count = - ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); - if (count != sizeof(chr)) - break; - if (chr != '\n') - continue; - - count = ksu_kernel_read_compat(fp, buf, sizeof(buf), - &line_start); - - struct uid_data *data = - kzalloc(sizeof(struct uid_data), GFP_ATOMIC); - if (!data) { - filp_close(fp, 0); - goto out; - } - - char *tmp = buf; - const char *delim = " "; - char *package = strsep(&tmp, delim); - char *uid = strsep(&tmp, delim); - if (!uid || !package) { - pr_err("update_uid: package or uid is NULL!\n"); - break; - } - - u32 res; - if (kstrtou32(uid, 10, &res)) { - pr_err("update_uid: uid parse err\n"); - break; - } - data->uid = res; - strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); - list_add_tail(&data->list, &uid_list); - // reset line start - line_start = pos; - } - filp_close(fp, 0); - - // now update uid list - struct uid_data *np; - struct uid_data *n; - - // first, check if manager_uid exist! - bool manager_exist = false; - list_for_each_entry (np, &uid_list, list) { - // if manager is installed in work profile, the uid in packages.list is still equals main profile - // don't delete it in this case! - int manager_uid = ksu_get_manager_uid() % 100000; - if (np->uid == manager_uid) { - manager_exist = true; - break; - } - } - - if (!manager_exist) { - if (ksu_is_manager_uid_valid()) { - pr_info("manager is uninstalled, invalidate it!\n"); - ksu_invalidate_manager_uid(); - goto prune; - } - pr_info("Searching manager...\n"); - search_manager("/data/app", 2, &uid_list); - pr_info("Search manager finished\n"); - } - -prune: - // then prune the allowlist - ksu_prune_allowlist(is_uid_exist, &uid_list); -out: - // free uid_list - list_for_each_entry_safe (np, n, &uid_list, list) { - list_del(&np->list); - kfree(np); - } -} - -void ksu_throne_tracker_init() -{ - // nothing to do -} - -void ksu_throne_tracker_exit() -{ - // nothing to do -} diff --git a/drivers/staging/kernelsu/throne_tracker.h b/drivers/staging/kernelsu/throne_tracker.h deleted file mode 100644 index 98bb9d5916f7..000000000000 --- a/drivers/staging/kernelsu/throne_tracker.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __KSU_H_UID_OBSERVER -#define __KSU_H_UID_OBSERVER - -void ksu_throne_tracker_init(); - -void ksu_throne_tracker_exit(); - -void ksu_track_throne(); - -bool is_lock_held(const char *path); - -#endif diff --git a/fs/namei.c b/fs/namei.c index dd4d922c8013..097df540aae0 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1022,6 +1022,12 @@ static inline int may_follow_link(struct nameidata *nd) const struct inode *inode; const struct inode *parent; kuid_t puid; + +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (nd->inode && unlikely(nd->inode->i_mapping->flags & BIT_SUS_PATH)) { + return -ENOENT; + } +#endif if (!sysctl_protected_symlinks) return 0; @@ -1099,6 +1105,12 @@ static bool safe_hardlink_source(struct inode *inode) static int may_linkat(struct path *link) { struct inode *inode = link->dentry->d_inode; + +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (link->dentry->d_inode && unlikely(link->dentry->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + return -ENOENT; + } +#endif /* Inode writeback is not safe when the uid or gid are invalid. */ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) @@ -1141,6 +1153,11 @@ static int may_linkat(struct path *link) static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid, struct inode * const inode) { +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (unlikely(inode->i_mapping->flags & BIT_SUS_PATH)) { + return -ENOENT; + } +#endif if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || @@ -1806,6 +1823,7 @@ static int lookup_fast(struct nameidata *nd, if (susfs_is_base_dentry_android_data_dir(parent) && susfs_is_sus_android_data_d_name_found(nd->last.name)) { + dput(dentry); dentry = __d_lookup(parent, &susfs_fake_qstr_name); goto skip_orig_flow2; } else if (susfs_is_base_dentry_sdcard_dir(parent) && @@ -2380,6 +2398,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) } #ifdef CONFIG_KSU_SUSFS_SUS_PATH if (nd->state & ND_STATE_LAST_SDCARD_SUS_PATH) { + // - No need to dput() here // return -ENOENT here since it is walking the sub path of sus sdcard path return -ENOENT; } @@ -2642,6 +2661,12 @@ static int filename_lookup(int dfd, struct filename *name, unsigned flags, if (likely(!retval)) audit_inode(name, path->dentry, flags & LOOKUP_PARENT); restore_nameidata(); +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (!retval && path->dentry->d_inode && unlikely(path->dentry->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + putname(name); + return -ENOENT; + } +#endif putname(name); return retval; } @@ -3123,6 +3148,11 @@ static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *vi return error; if (IS_APPEND(dir)) return -EPERM; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (unlikely(inode->i_mapping->flags & BIT_SUS_PATH)) { + return -ENOENT; + } +#endif if (check_sticky(dir, inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode)) @@ -3152,8 +3182,20 @@ static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *vi */ static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) { - struct user_namespace *s_user_ns; - audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + int error; +#endif + struct user_namespace *s_user_ns; + audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (child->d_inode && unlikely(child->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + if (error) { + return error; + } + return -ENOENT; + } +#endif if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) @@ -3283,6 +3325,12 @@ static int may_open(const struct path *path, int acc_mode, int flag) if (!inode) return -ENOENT; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (unlikely(inode->i_mapping->flags & BIT_SUS_PATH)) { + return -ENOENT; + } +#endif + switch (inode->i_mode & S_IFMT) { case S_IFLNK: return -ELOOP; @@ -3354,7 +3402,20 @@ static inline int open_to_namei_flags(int flag) static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode) { struct user_namespace *s_user_ns; - int error = security_path_mknod(dir, dentry, mode, 0); +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + int error; + + if (dentry->d_inode && unlikely(dentry->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); + if (error) { + return error; + } + return -ENOENT; + } + error = security_path_mknod(dir, dentry, mode, 0); +#else + int error = security_path_mknod(dir, dentry, mode, 0); +#endif if (error) return error; @@ -3481,6 +3542,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, if (susfs_is_base_dentry_android_data_dir(dir) && susfs_is_sus_android_data_d_name_found(nd->last.name)) { + dput(dentry); dentry = d_lookup(dir, &susfs_fake_qstr_name); found_sus_path = true; goto skip_orig_flow1; @@ -3534,6 +3596,12 @@ static int lookup_open(struct nameidata *nd, struct path *path, } if (dentry->d_inode) { /* Cached positive dentry: will open in f_op->open */ +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (unlikely(dentry->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + dput(dentry); + return -ENOENT; + } +#endif goto out_no_open; } @@ -3577,6 +3645,16 @@ static int lookup_open(struct nameidata *nd, struct path *path, mode); if (unlikely(error == -ENOENT) && create_error) error = create_error; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + if (create_error) { + dput(dentry); + return create_error; + } + dput(dentry); + return -ENOENT; + } +#endif return error; } @@ -3592,6 +3670,12 @@ static int lookup_open(struct nameidata *nd, struct path *path, } dput(dentry); dentry = res; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (dentry->d_inode && unlikely(dentry->d_inode->i_mapping->flags & BIT_SUS_PATH)) { + dput(dentry); + return -ENOENT; + } +#endif } } @@ -3953,7 +4037,7 @@ struct file *do_filp_open(int dfd, struct filename *pathname, if (unlikely(filp == ERR_PTR(-ESTALE))) filp = path_openat(&nd, op, flags | LOOKUP_REVAL); #ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT - if (!IS_ERR(filp) && unlikely(filp->f_inode->i_mapping->flags & BIT_OPEN_REDIRECT) && current_uid().val < 2000) { + if (!IS_ERR(filp) && unlikely(filp->f_inode->i_mapping->flags & BIT_OPEN_REDIRECT) && current_uid().val < 11000) { fake_pathname = susfs_get_redirected_path(filp->f_inode->i_ino); if (!IS_ERR(fake_pathname)) { restore_nameidata(); diff --git a/fs/namespace.c b/fs/namespace.c index b136bda30021..50f459d97c21 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -36,9 +36,10 @@ #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT extern bool susfs_is_current_ksu_domain(void); extern bool susfs_is_current_zygote_domain(void); +extern bool susfs_is_boot_completed_triggered; -static DEFINE_IDA(susfs_mnt_id_ida); -static DEFINE_IDA(susfs_mnt_group_ida); +static DEFINE_IDA(susfs_ksu_mnt_id_ida); +static DEFINE_IDA(susfs_ksu_mnt_group_ida); #define CL_COPY_MNT_NS BIT(25) /* used by copy_mnt_ns() */ #endif @@ -123,10 +124,10 @@ static inline struct hlist_head *mp_hash(struct dentry *dentry) } #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT -// Our own mnt_alloc_id() that assigns mnt_id starting from DEFAULT_SUS_MNT_ID +// Our own mnt_alloc_id() that assigns mnt_id starting from DEFAULT_KSU_MNT_ID static int susfs_mnt_alloc_id(struct mount *mnt) { - int res = ida_alloc_min(&susfs_mnt_id_ida, DEFAULT_SUS_MNT_ID, GFP_KERNEL); + int res = ida_alloc_min(&susfs_ksu_mnt_id_ida, DEFAULT_KSU_MNT_ID, GFP_KERNEL); if (res < 0) return res; @@ -147,14 +148,14 @@ static int mnt_alloc_id(struct mount *mnt) static void mnt_free_id(struct mount *mnt) { #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // We should first check the 'mnt->mnt.susfs_mnt_id_backup', see if it is DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE + // We should first check the 'mnt->mnt.susfs_mnt_id_backup', see if it is DEFAULT_KSU_MNT_ID_FOR_KSU_PROC_UNSHARE // if so, these mnt_id were not assigned by mnt_alloc_id() so we don't need to free it. - if (unlikely(mnt->mnt.susfs_mnt_id_backup == DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE)) { + if (unlikely(mnt->mnt.susfs_mnt_id_backup == DEFAULT_KSU_MNT_ID_FOR_KSU_PROC_UNSHARE)) { return; } // Now we can check if its mnt_id is sus - if (unlikely(mnt->mnt_id >= DEFAULT_SUS_MNT_ID)) { - ida_free(&susfs_mnt_id_ida, mnt->mnt_id); + if (unlikely(mnt->mnt_id >= DEFAULT_KSU_MNT_ID)) { + ida_free(&susfs_ksu_mnt_id_ida, mnt->mnt_id); return; } // Lastly if 'mnt->mnt.susfs_mnt_id_backup' is not 0, then it contains a backup origin mnt_id @@ -178,9 +179,9 @@ static int mnt_alloc_group_id(struct mount *mnt) int res; // Check if mnt has sus mnt_id - if (mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { - // If so, assign a sus mnt_group id DEFAULT_SUS_MNT_GROUP_ID from susfs_mnt_group_ida - res = ida_alloc_min(&susfs_mnt_group_ida, DEFAULT_SUS_MNT_GROUP_ID, GFP_KERNEL); + if (mnt->mnt_id >= DEFAULT_KSU_MNT_ID) { + // If so, assign a sus mnt_group id DEFAULT_KSU_MNT_GROUP_ID from susfs_ksu_mnt_group_ida + res = ida_alloc_min(&susfs_ksu_mnt_group_ida, DEFAULT_KSU_MNT_GROUP_ID, GFP_KERNEL); goto bypass_orig_flow; } res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL); @@ -201,10 +202,10 @@ static int mnt_alloc_group_id(struct mount *mnt) void mnt_release_group_id(struct mount *mnt) { #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // If mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID, it means 'mnt' is also sus mount, - // then we free the mnt->mnt_group_id from susfs_mnt_group_ida - if (mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID) { - ida_free(&susfs_mnt_group_ida, mnt->mnt_group_id); + // If mnt->mnt_group_id >= DEFAULT_KSU_MNT_GROUP_ID, it means 'mnt' is also sus mount, + // then we free the mnt->mnt_group_id from susfs_ksu_mnt_group_ida + if (mnt->mnt_group_id >= DEFAULT_KSU_MNT_GROUP_ID) { + ida_free(&susfs_ksu_mnt_group_ida, mnt->mnt_group_id); mnt->mnt_group_id = 0; return; } @@ -1094,7 +1095,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void mnt->mnt_parent = mnt; #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // - If caller process is zygote, then it is a normal mount, so we calculate the next available + // - If caller process is zygote, then it is a normal mount, so we calculate the next available // fake mnt_id for this mount if (susfs_is_current_zygote_domain()) { mnt_ns = current->nsproxy->mnt_ns; @@ -1103,7 +1104,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void rcu_read_lock(); mnt_id = list_first_entry(&mnt_ns->list, struct mount, mnt_list)->mnt_id; list_for_each_entry_rcu(m, &mnt_ns->list, mnt_list) { - if (m->mnt_id < DEFAULT_SUS_MNT_ID) { + if (m->mnt_id < DEFAULT_KSU_MNT_ID) { mnt_id++; } } @@ -1151,7 +1152,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, bool is_current_ksu_domain = susfs_is_current_ksu_domain(); bool is_current_zygote_domain = susfs_is_current_zygote_domain(); - /* - It is very important that we need to use CL_COPY_MNT_NS to identify whether + /* - It is very important that we need to use CL_COPY_MNT_NS to identify whether * the clone is a copy_tree() or single mount like called by __do_loopback() * - if caller process is KSU, consider the following situation: * 1. it is NOT doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id @@ -1171,12 +1172,12 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, // if it is doing unshare mnt = alloc_vfsmnt(old->mnt_devname, true, old->mnt_id); if (mnt) { - mnt->mnt.susfs_mnt_id_backup = DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE; + mnt->mnt.susfs_mnt_id_backup = DEFAULT_KSU_MNT_ID_FOR_KSU_PROC_UNSHARE; } goto bypass_orig_flow; } // Lastly, just check if old->mnt_id is sus - if (old->mnt_id >= DEFAULT_SUS_MNT_ID) { + if (old->mnt_id >= DEFAULT_KSU_MNT_ID) { mnt = alloc_vfsmnt(old->mnt_devname, true, 0); goto bypass_orig_flow; } @@ -1251,7 +1252,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, get_mnt_ns(mnt_ns); mnt_id = list_first_entry(&mnt_ns->list, struct mount, mnt_list)->mnt_id; list_for_each_entry_rcu(m, &mnt_ns->list, mnt_list) { - if (m->mnt_id < DEFAULT_SUS_MNT_ID) { + if (m->mnt_id < DEFAULT_KSU_MNT_ID) { mnt_id++; } } @@ -1973,9 +1974,9 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, int flag) { struct mount *res, *p, *q, *r, *parent; - #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - bool is_current_zygote_domain = susfs_is_current_zygote_domain(); - #endif +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + bool is_zygote_not_copy_mnt_ns = (susfs_is_current_zygote_domain() && !(flag & CL_COPY_MNT_NS)); +#endif if (!(flag & CL_COPY_UNBINDABLE) && IS_MNT_UNBINDABLE(mnt)) return ERR_PTR(-EINVAL); @@ -1992,10 +1993,9 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, p = mnt; list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { struct mount *s; - #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT int attach_mnt_count = 0; - #endif - +#endif if (!is_subdir(r->mnt_mountpoint, dentry)) continue; @@ -2025,18 +2025,16 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, q = clone_mnt(p, p->mnt.mnt_root, flag); if (IS_ERR(q)) goto out; +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + if (is_zygote_not_copy_mnt_ns && + q->mnt_id < DEFAULT_KSU_MNT_ID) { + attach_mnt_count++; + q->mnt_id += attach_mnt_count; + } +#endif lock_mount_hash(); list_add_tail(&q->mnt_list, &res->mnt_list); attach_mnt(q, parent, p->mnt_mp); - #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (is_current_zygote_domain && - !(flag & CL_COPY_MNT_NS) && - q->mnt_id < DEFAULT_SUS_MNT_ID) - { - attach_mnt_count++; - q->mnt_id += attach_mnt_count; - } - #endif unlock_mount_hash(); } } @@ -3123,15 +3121,6 @@ long do_mount(const char *dev_name, const char __user *dir_name, else retval = do_new_mount(&path, type_page, sb_flags, mnt_flags, dev_name, data_page); -#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT - // For both Legacy and Magic Mount KernelSU - if (!retval && susfs_is_auto_add_sus_ksu_default_mount_enabled && - (!(flags & (MS_REMOUNT | MS_BIND | MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)))) { - if (susfs_is_current_ksu_domain()) { - susfs_auto_add_sus_ksu_default_mount(dir_name); - } - } -#endif dput_out: path_put(&path); return retval; @@ -3253,6 +3242,12 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, */ p = old; q = new; +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + if (likely(is_zygote_pid)) { + last_entry_mnt_id = new->mnt_id; + q->mnt.susfs_mnt_id_backup = new->mnt_id; + } +#endif while (p) { q->mnt_ns = new_ns; new_ns->mounts++; @@ -3270,26 +3265,18 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, q = next_mnt(q, new); if (!q) break; - while (p->mnt.mnt_root != q->mnt.mnt_root) - p = next_mnt(p, old); - } #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - // q->mnt.susfs_mnt_id_backup -> original mnt_id - // q->mnt_id -> will be modified to the fake mnt_id - - // Here We are only interested in processes of which original mnt namespace belongs to zygote - // Also we just make use of existing 'q' mount pointer, no need to delcare extra mount pointer - if (is_zygote_pid) { - last_entry_mnt_id = list_first_entry(&new_ns->list, struct mount, mnt_list)->mnt_id; - list_for_each_entry(q, &new_ns->list, mnt_list) { - if (unlikely(q->mnt_id >= DEFAULT_SUS_MNT_ID)) { - continue; - } + // Here We are only interested in processes of which original mnt namespace belongs to zygote + if (likely(is_zygote_pid && (q->mnt_id < DEFAULT_KSU_MNT_ID))) { + // q->mnt.susfs_mnt_id_backup -> original mnt_id + // q->mnt_id -> to be modified to the fake mnt_id q->mnt.susfs_mnt_id_backup = q->mnt_id; - q->mnt_id = last_entry_mnt_id++; + q->mnt_id = ++last_entry_mnt_id; } - } #endif + while (p->mnt.mnt_root != q->mnt.mnt_root) + p = next_mnt(p, old); + } namespace_unlock(); @@ -3849,7 +3836,7 @@ void susfs_run_try_umount_for_current_mnt_ns(void) { namespace_lock(); list_for_each_entry(mnt, &mnt_ns->list, mnt_list) { // Change the sus mount to be private - if (mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { + if (mnt->mnt_id >= DEFAULT_KSU_MNT_ID) { change_mnt_propagation(mnt, MS_PRIVATE); } } @@ -3858,6 +3845,26 @@ void susfs_run_try_umount_for_current_mnt_ns(void) { susfs_try_umount_all(current_uid().val); } #endif +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +/* Reorder the mnt_id after all sus mounts are umounted during ksu_handle_setuid() */ +void susfs_reorder_mnt_id(void) { + struct mnt_namespace *mnt_ns = current->nsproxy->mnt_ns; + struct mount *mnt; + int first_mnt_id = 0; + + if (!mnt_ns) { + return; + } + + get_mnt_ns(mnt_ns); + first_mnt_id = list_first_entry(&mnt_ns->list, struct mount, mnt_list)->mnt_id; + list_for_each_entry(mnt, &mnt_ns->list, mnt_list) { + mnt->mnt.susfs_mnt_id_backup = mnt->mnt_id; + mnt->mnt_id = first_mnt_id++; + } + put_mnt_ns(mnt_ns); +} +#endif #ifdef CONFIG_KSU_SUSFS bool susfs_is_mnt_devname_ksu(struct path *path) { struct mount *mnt; diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 22c3cf697fde..a129413d79fc 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c @@ -102,7 +102,7 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) inode = igrab(fsnotify_conn_inode(mark->connector)); if (inode) { #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (likely(susfs_is_current_non_root_user_app_proc()) && + if (likely(susfs_is_current_proc_umounted()) && unlikely(inode->i_mapping->flags & BIT_SUS_KSTAT)) { struct path path; char *pathname = kmalloc(PAGE_SIZE, GFP_KERNEL); diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 63c897de86e7..598130aeb5ea 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -61,9 +61,9 @@ static int seq_show(struct seq_file *m, void *v) #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT mnt = real_mount(file->f_path.mnt); - if (likely(susfs_is_current_non_root_user_app_proc()) && - mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { - for (; mnt->mnt_id >= DEFAULT_SUS_MNT_ID; mnt = mnt->mnt_parent) { } + if (likely(susfs_is_current_proc_umounted()) && + mnt->mnt_id >= DEFAULT_KSU_MNT_ID) { + for (; mnt->mnt_id >= DEFAULT_KSU_MNT_ID; mnt = mnt->mnt_parent) { } } seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", (long long)file->f_pos, f_flags, diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index f12d5b1cff1a..4561441af7e6 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -110,7 +110,7 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) int err; #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_SUS_MNT_ID) { + if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_KSU_MNT_ID) { return 0; } #endif @@ -152,7 +152,7 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) int err; #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_SUS_MNT_ID) { + if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_KSU_MNT_ID) { return 0; } #endif @@ -222,7 +222,7 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) int err; #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT - if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_SUS_MNT_ID) { + if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_KSU_MNT_ID) { return 0; } #endif diff --git a/fs/stat.c b/fs/stat.c index 77f22df2943a..fc75bca63432 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -40,7 +40,7 @@ extern void susfs_sus_ino_for_generic_fillattr(unsigned long ino, struct kstat * void generic_fillattr(struct inode *inode, struct kstat *stat) { #ifdef CONFIG_KSU_SUSFS_SUS_KSTAT - if (likely(susfs_is_current_non_root_user_app_proc()) && + if (likely(susfs_is_current_proc_umounted()) && unlikely(inode->i_mapping->flags & BIT_SUS_KSTAT)) { susfs_sus_ino_for_generic_fillattr(inode->i_ino, stat); stat->mode = inode->i_mode; diff --git a/fs/statfs.c b/fs/statfs.c index 89707f618893..d77ca40ddfad 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -78,8 +78,8 @@ int vfs_statfs(const struct path *path, struct kstatfs *buf) struct mount *mnt; mnt = real_mount(path->mnt); - if (likely(susfs_is_current_non_root_user_app_proc())) { - for (; mnt->mnt_id >= DEFAULT_SUS_MNT_ID; mnt = mnt->mnt_parent) {} + if (likely(susfs_is_current_proc_umounted())) { + for (; mnt->mnt_id >= DEFAULT_KSU_MNT_ID; mnt = mnt->mnt_parent) {} } error = statfs_by_dentry(mnt->mnt.mnt_root, buf); if (!error) diff --git a/fs/susfs.c b/fs/susfs.c index 3adf50ac0223..c4a88b226627 100644 --- a/fs/susfs.c +++ b/fs/susfs.c @@ -21,18 +21,27 @@ static spinlock_t susfs_spin_lock; extern bool susfs_is_current_ksu_domain(void); #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT -extern void ksu_try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid); +extern void try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid); #endif +extern bool susfs_is_avc_log_spoofing_enabled; #ifdef CONFIG_KSU_SUSFS_ENABLE_LOG bool susfs_is_log_enabled __read_mostly = true; #define SUSFS_LOGI(fmt, ...) if (susfs_is_log_enabled) pr_info("susfs:[%u][%d][%s] " fmt, current_uid().val, current->pid, __func__, ##__VA_ARGS__) #define SUSFS_LOGE(fmt, ...) if (susfs_is_log_enabled) pr_err("susfs:[%u][%d][%s]" fmt, current_uid().val, current->pid, __func__, ##__VA_ARGS__) #else -#define SUSFS_LOGI(fmt, ...) -#define SUSFS_LOGE(fmt, ...) +#define SUSFS_LOGI(fmt, ...) +#define SUSFS_LOGE(fmt, ...) #endif +bool susfs_starts_with(const char *str, const char *prefix) { + while (*prefix) { + if (*str++ != *prefix++) + return false; + } + return true; +} + /* sus_path */ #ifdef CONFIG_KSU_SUSFS_SUS_PATH static LIST_HEAD(LH_SUS_PATH_LOOP); @@ -82,7 +91,7 @@ int susfs_set_i_state_on_external_dir(char __user* user_info, int cmd) { err = -EINVAL; goto out_path_put_path; } - + if (cmd == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) { spin_lock(&inode->i_lock); set_bit(AS_FLAGS_ANDROID_DATA_ROOT_DIR, &inode->i_mapping->flags); @@ -126,7 +135,7 @@ int susfs_add_sus_path(struct st_susfs_sus_path* __user user_info) { return err; } - err = kern_path(info.target_pathname, 0, &path); + err = kern_path(info.target_pathname, LOOKUP_FOLLOW, &path); if (err) { SUSFS_LOGE("Failed opening file '%s'\n", info.target_pathname); return err; @@ -340,16 +349,16 @@ void susfs_run_sus_path_loop(uid_t uid) { } static inline bool is_i_uid_in_android_data_not_allowed(uid_t i_uid) { - return (likely(susfs_is_current_non_root_user_app_proc()) && + return (likely(susfs_is_current_proc_umounted()) && unlikely(current_uid().val != i_uid)); } static inline bool is_i_uid_in_sdcard_not_allowed(void) { - return (likely(susfs_is_current_non_root_user_app_proc())); + return (likely(susfs_is_current_proc_umounted())); } static inline bool is_i_uid_not_allowed(uid_t i_uid) { - return (likely(susfs_is_current_non_root_user_app_proc()) && + return (likely(susfs_is_current_proc_umounted()) && unlikely(current_uid().val != i_uid)); } @@ -442,7 +451,7 @@ static void susfs_update_sus_mount_inode(char *target_pathname) { struct inode *inode = NULL; int err = 0; - err = kern_path(target_pathname, LOOKUP_FOLLOW, &p); + err = kern_path(target_pathname, 0, &p); if (err) { SUSFS_LOGE("Failed opening file '%s'\n", target_pathname); return; @@ -455,7 +464,7 @@ static void susfs_update_sus_mount_inode(char *target_pathname) { */ mnt = real_mount(p.mnt); if (mnt->mnt_group_id > 0 && // 0 means no peer group - mnt->mnt_group_id < DEFAULT_SUS_MNT_GROUP_ID) { + mnt->mnt_group_id < DEFAULT_KSU_MNT_GROUP_ID) { SUSFS_LOGE("skip setting SUS_MOUNT inode state for path '%s' since its source mount has a legit peer group id\n", target_pathname); return; } @@ -532,7 +541,7 @@ int susfs_auto_add_sus_bind_mount(const char *pathname, struct path *path_target mnt = real_mount(path_target->mnt); if (mnt->mnt_group_id > 0 && // 0 means no peer group - mnt->mnt_group_id < DEFAULT_SUS_MNT_GROUP_ID) { + mnt->mnt_group_id < DEFAULT_KSU_MNT_GROUP_ID) { SUSFS_LOGE("skip setting SUS_MOUNT inode state for path '%s' since its source mount has a legit peer group id\n", pathname); // return 0 here as we still want it to be added to try_umount list return 0; @@ -605,7 +614,7 @@ static int susfs_update_sus_kstat_inode(char *target_pathname) { struct inode *inode = NULL; int err = 0; - err = kern_path(target_pathname,0, &p); + err = kern_path(target_pathname, LOOKUP_FOLLOW, &p); if (err) { SUSFS_LOGE("Failed opening file '%s'\n", target_pathname); return 1; @@ -849,9 +858,9 @@ void susfs_try_umount(uid_t target_uid) { // We should umount in reversed order list_for_each_entry_reverse(cursor, &LH_TRY_UMOUNT_PATH, list) { if (cursor->info.mnt_mode == TRY_UMOUNT_DEFAULT) { - ksu_try_umount(cursor->info.target_pathname, false, 0, target_uid); + try_umount(cursor->info.target_pathname, false, 0, target_uid); } else if (cursor->info.mnt_mode == TRY_UMOUNT_DETACH) { - ksu_try_umount(cursor->info.target_pathname, false, MNT_DETACH, target_uid); + try_umount(cursor->info.target_pathname, false, MNT_DETACH, target_uid); } else { SUSFS_LOGE("failed umounting '%s' for uid: %d, mnt_mode '%d' not supported\n", cursor->info.target_pathname, target_uid, cursor->info.mnt_mode); @@ -1106,7 +1115,7 @@ int susfs_add_open_redirect(struct st_susfs_open_redirect* __user user_info) { hash_add(OPEN_REDIRECT_HLIST, &new_entry->node, info.target_ino); if (update_hlist) { SUSFS_LOGI("target_ino: '%lu', target_pathname: '%s', redirected_pathname: '%s', is successfully updated to OPEN_REDIRECT_HLIST\n", - new_entry->target_ino, new_entry->target_pathname, new_entry->redirected_pathname); + new_entry->target_ino, new_entry->target_pathname, new_entry->redirected_pathname); } else { SUSFS_LOGI("target_ino: '%lu', target_pathname: '%s' redirected_pathname: '%s', is successfully added to OPEN_REDIRECT_HLIST\n", new_entry->target_ino, new_entry->target_pathname, new_entry->redirected_pathname); @@ -1128,66 +1137,6 @@ struct filename* susfs_get_redirected_path(unsigned long ino) { } #endif // #ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT -/* sus_su */ -#ifdef CONFIG_KSU_SUSFS_SUS_SU -bool susfs_is_sus_su_hooks_enabled __read_mostly = false; -static int susfs_sus_su_working_mode = 0; -extern void ksu_susfs_enable_sus_su(void); -extern void ksu_susfs_disable_sus_su(void); - -int susfs_get_sus_su_working_mode(void) { - return susfs_sus_su_working_mode; -} - -int susfs_sus_su(struct st_sus_su* __user user_info) { - struct st_sus_su info; - int last_working_mode = susfs_sus_su_working_mode; - - if (copy_from_user(&info, user_info, sizeof(struct st_sus_su))) { - SUSFS_LOGE("failed copying from userspace\n"); - return 1; - } - - if (info.mode == SUS_SU_WITH_HOOKS) { - if (last_working_mode == SUS_SU_WITH_HOOKS) { - SUSFS_LOGE("current sus_su mode is already %d\n", SUS_SU_WITH_HOOKS); - return 1; - } - if (last_working_mode != SUS_SU_DISABLED) { - SUSFS_LOGE("please make sure the current sus_su mode is %d first\n", SUS_SU_DISABLED); - return 2; - } - ksu_susfs_enable_sus_su(); - susfs_sus_su_working_mode = SUS_SU_WITH_HOOKS; - susfs_is_sus_su_hooks_enabled = true; - SUSFS_LOGI("core kprobe hooks for ksu are disabled!\n"); - SUSFS_LOGI("non-kprobe hook sus_su is enabled!\n"); - SUSFS_LOGI("sus_su mode: %d\n", SUS_SU_WITH_HOOKS); - return 0; - } else if (info.mode == SUS_SU_DISABLED) { - if (last_working_mode == SUS_SU_DISABLED) { - SUSFS_LOGE("current sus_su mode is already %d\n", SUS_SU_DISABLED); - return 1; - } - susfs_is_sus_su_hooks_enabled = false; - ksu_susfs_disable_sus_su(); - susfs_sus_su_working_mode = SUS_SU_DISABLED; - if (last_working_mode == SUS_SU_WITH_HOOKS) { - SUSFS_LOGI("core kprobe hooks for ksu are enabled!\n"); - goto out; - } -out: - if (copy_to_user(user_info, &info, sizeof(info))) - SUSFS_LOGE("copy_to_user() failed\n"); - return 0; - } else if (info.mode == SUS_SU_WITH_OVERLAY) { - SUSFS_LOGE("sus_su mode %d is deprecated\n", SUS_SU_WITH_OVERLAY); - return 1; - } - return 1; -} -#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU - static int copy_config_to_buf(const char *config_string, char *buf_ptr, size_t *copied_size, size_t bufsize) { size_t tmp_size = strlen(config_string); @@ -1271,6 +1220,11 @@ int susfs_get_enabled_features(char __user* buf, size_t bufsize) { if (err) goto out_kfree_kbuf; buf_ptr = kbuf + copied_size; #endif +#ifdef CONFIG_KSU_SUSFS_SUS_SU + err = copy_config_to_buf("CONFIG_KSU_SUSFS_SUS_SU\n", buf_ptr, &copied_size, bufsize); + if (err) goto out_kfree_kbuf; + buf_ptr = kbuf + copied_size; +#endif #ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT err = copy_config_to_buf("CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT\n", buf_ptr, &copied_size, bufsize); if (err) goto out_kfree_kbuf; @@ -1282,6 +1236,14 @@ int susfs_get_enabled_features(char __user* buf, size_t bufsize) { return err; } +/* susfs avc log spoofing */ +void susfs_set_avc_log_spoofing(bool enabled) { + spin_lock(&susfs_spin_lock); + susfs_is_avc_log_spoofing_enabled = enabled; + spin_unlock(&susfs_spin_lock); + SUSFS_LOGI("enabled: %d\n", enabled); +} + /* susfs_init */ void susfs_init(void) { spin_lock_init(&susfs_spin_lock); diff --git a/include/linux/sched.h b/include/linux/sched.h index ed5bd81a8129..387e8a729a3c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1533,9 +1533,6 @@ struct task_struct { ANDROID_KABI_RESERVE(5); ANDROID_KABI_RESERVE(6); #else -#if defined(CONFIG_KSU_SUSFS) - u64 susfs_task_state; -#endif struct mutex futex_exit_mutex; #endif @@ -1551,9 +1548,6 @@ struct task_struct { * New fields for task_struct should be added above here, so that * they are included in the randomized portion of task_struct. */ -#if defined(CONFIG_KSU_SUSFS) && !defined(ANDROID_KABI_RESERVE) - u64 susfs_task_state; -#endif #if defined(CONFIG_KSU_SUSFS) && !defined(ANDROID_KABI_RESERVE) u64 susfs_last_fake_mnt_id; #endif diff --git a/include/linux/susfs.h b/include/linux/susfs.h index d1ca78b97ad4..bcf52e926669 100644 --- a/include/linux/susfs.h +++ b/include/linux/susfs.h @@ -8,7 +8,7 @@ #include #include -#define SUSFS_VERSION "v1.5.9" +#define SUSFS_VERSION "v1.5.11" #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) #define SUSFS_VARIANT "NON-GKI" #else @@ -194,6 +194,7 @@ int susfs_sus_su(struct st_sus_su* __user user_info); #endif int susfs_get_enabled_features(char __user* buf, size_t bufsize); +void susfs_set_avc_log_spoofing(bool enabled); /* susfs_init */ void susfs_init(void); diff --git a/include/linux/susfs_def.h b/include/linux/susfs_def.h index 512a57b498fb..b015c60e247a 100644 --- a/include/linux/susfs_def.h +++ b/include/linux/susfs_def.h @@ -22,10 +22,10 @@ #define CMD_SUSFS_ENABLE_LOG 0x555a0 #define CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG 0x555b0 #define CMD_SUSFS_ADD_OPEN_REDIRECT 0x555c0 -#define CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS 0x555d0 #define CMD_SUSFS_SHOW_VERSION 0x555e1 #define CMD_SUSFS_SHOW_ENABLED_FEATURES 0x555e2 #define CMD_SUSFS_SHOW_VARIANT 0x555e3 +#define CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING 0x60010 #define CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE 0x555e4 #define CMD_SUSFS_IS_SUS_SU_READY 0x555f0 #define CMD_SUSFS_SUS_SU 0x60000 @@ -40,20 +40,17 @@ #define SUS_SU_WITH_OVERLAY 1 /* deprecated */ #define SUS_SU_WITH_HOOKS 2 -#define DEFAULT_SUS_MNT_ID 100000 /* used by mount->mnt_id */ -#define DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE 1000000 /* used by vfsmount->susfs_mnt_id_backup */ -#define DEFAULT_SUS_MNT_GROUP_ID 1000 /* used by mount->mnt_group_id */ +#define DEFAULT_KSU_MNT_ID 300000 /* used by mount->mnt_id */ +#define DEFAULT_KSU_MNT_ID_FOR_KSU_PROC_UNSHARE 1000000 /* used by vfsmount->susfs_mnt_id_backup */ +#define DEFAULT_KSU_MNT_GROUP_ID 3000 /* used by mount->mnt_group_id */ /* * mount->mnt.susfs_mnt_id_backup => storing original mnt_id of normal mounts or custom sus mnt_id of sus mounts - * inode->i_mapping->flags => storing flag 'AS_FLAGS_' * nd->state => storing flag 'ND_STATE_' * nd->flags => storing flag 'ND_FLAGS_' * task_struct->thread_info.flags => storing flag 'TIF_' */ -// thread_info->flags is unsigned long :D -#define TIF_NON_ROOT_USER_APP_PROC 33 -#define TIF_PROC_SU_NOT_ALLOWED 34 +#define TIF_PROC_UMOUNTED 33 #define AS_FLAGS_SUS_PATH 24 #define AS_FLAGS_SUS_MOUNT 25 @@ -79,27 +76,11 @@ #define DATA_ADB_NO_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT "/data/adb/susfs_no_auto_add_sus_ksu_default_mount" #define DATA_ADB_NO_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT "/data/adb/susfs_no_auto_add_try_umount_for_bind_mount" -static inline bool susfs_is_current_non_root_user_app_proc(void) { - return test_ti_thread_flag(¤t->thread_info, TIF_NON_ROOT_USER_APP_PROC); +static inline bool susfs_is_current_proc_umounted(void) { + return test_ti_thread_flag(¤t->thread_info, TIF_PROC_UMOUNTED); } -static inline void susfs_set_current_non_root_user_app_proc(void) { - set_ti_thread_flag(¤t->thread_info, TIF_NON_ROOT_USER_APP_PROC); -} - -static inline bool susfs_is_current_proc_su_not_allowed(void) { - return test_ti_thread_flag(¤t->thread_info, TIF_PROC_SU_NOT_ALLOWED); -} - -static inline void susfs_set_current_proc_su_not_allowed(void) { - set_ti_thread_flag(¤t->thread_info, TIF_PROC_SU_NOT_ALLOWED); -} - -static inline bool susfs_starts_with(const char *str, const char *prefix) { - while (*prefix) { - if (*str++ != *prefix++) - return false; - } - return true; +static inline void susfs_set_current_proc_umounted(void) { + set_ti_thread_flag(¤t->thread_info, TIF_PROC_UMOUNTED); } #endif // #ifndef KSU_SUSFS_DEF_H diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index ac31db1714d5..0611dfac5de2 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -753,6 +753,10 @@ static void *s_start(struct seq_file *m, loff_t *pos) return m->private; } +#ifdef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS +extern bool susfs_starts_with(const char *str, const char *prefix); +#endif + static void s_stop(struct seq_file *m, void *p) { } @@ -785,7 +789,25 @@ static int s_show(struct seq_file *m, void *p) iter->type, iter->name); #else { - if (strstr(iter->name, "ksu_") || !strncmp(iter->name, "susfs_", 6) || !strncmp(iter->name, "ksud", 4)) { + if (susfs_starts_with(iter->name, "ksu_") || + susfs_starts_with(iter->name, "__ksu_") || + susfs_starts_with(iter->name, "susfs_") || + susfs_starts_with(iter->name, "ksud") || + susfs_starts_with(iter->name, "is_ksu_") || + susfs_starts_with(iter->name, "is_manager_") || + susfs_starts_with(iter->name, "escape_to_") || + susfs_starts_with(iter->name, "setup_selinux") || + susfs_starts_with(iter->name, "track_throne") || + susfs_starts_with(iter->name, "on_post_fs_data") || + susfs_starts_with(iter->name, "try_umount") || + susfs_starts_with(iter->name, "kernelsu") || + susfs_starts_with(iter->name, "__initcall__kmod_kernelsu") || + susfs_starts_with(iter->name, "apply_kernelsu") || + susfs_starts_with(iter->name, "handle_sepolicy") || + susfs_starts_with(iter->name, "getenforce") || + susfs_starts_with(iter->name, "setenforce") || + susfs_starts_with(iter->name, "is_zygote")) + { return 0; } seq_printf(m, "%px %c %s\n", value, diff --git a/security/selinux/avc.c b/security/selinux/avc.c index a6be33ae7738..61b7d7f4a4f1 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -165,6 +165,11 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) audit_log_format(ab, " }"); } +#ifdef CONFIG_KSU_SUSFS +extern u32 susfs_ksu_sid; +extern u32 susfs_kernel_sid; +bool susfs_is_avc_log_spoofing_enabled = false; +#endif /** * avc_dump_query - Display a SID pair and a class in human-readable form. @@ -178,8 +183,20 @@ static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state, int rc; char *scontext; u32 scontext_len; +#ifdef CONFIG_KSU_SUSFS + struct selinux_audit_data sad; +#endif rc = security_sid_to_context(state, ssid, &scontext, &scontext_len); +#ifdef CONFIG_KSU_SUSFS + if (unlikely(sad.tsid == susfs_ksu_sid)) { + if (rc) + audit_log_format(ab, " tsid=%d", susfs_kernel_sid && susfs_is_avc_log_spoofing_enabled); + else + audit_log_format(ab, " tcontext=%s", "u:r:kernel:s0"); + goto bypass_orig_flow; + } +#endif if (rc) audit_log_format(ab, "ssid=%d", ssid); else { @@ -187,6 +204,9 @@ static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state, kfree(scontext); } +#ifdef CONFIG_KSU_SUSFS +bypass_orig_flow: +#endif rc = security_sid_to_context(state, tsid, &scontext, &scontext_len); if (rc) audit_log_format(ab, " tsid=%d", tsid);