kernel: susfs 1.5.9 a13-5.15 patch

This commit is contained in:
Rifat Azad
2025-07-15 22:23:43 +06:00
parent 52112a7ee3
commit 6fe4fcbce0
19 changed files with 1037 additions and 95 deletions

View File

@@ -40,4 +40,139 @@ config KSU_LSM_SECURITY_HOOKS
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
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

View File

@@ -21,7 +21,7 @@ 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) + 200))
$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 198))
$(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.
@@ -116,4 +116,81 @@ 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

View File

@@ -95,7 +95,7 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
static struct work_struct ksu_save_work;
static struct work_struct ksu_load_work;
bool persistent_allow_list(void);
static bool persistent_allow_list(void);
void ksu_show_allow_list(void)
{
@@ -266,7 +266,7 @@ bool __ksu_is_allow_uid(uid_t uid)
if (unlikely(uid == 0)) {
// already root, but only allow our domain.
return is_ksu_domain();
return ksu_is_ksu_domain();
}
if (forbid_system_uid(uid)) {
@@ -351,7 +351,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true;
}
void do_save_allow_list(struct work_struct *work)
static void do_save_allow_list(struct work_struct *work)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
@@ -393,7 +393,7 @@ exit:
filp_close(fp, 0);
}
void do_load_allow_list(struct work_struct *work)
static void do_load_allow_list(struct work_struct *work)
{
loff_t off = 0;
ssize_t ret = 0;
@@ -483,7 +483,7 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data
}
// make sure allow list works cross boot
bool persistent_allow_list(void)
static bool persistent_allow_list(void)
{
return ksu_queue_work(&ksu_save_work);
}

View File

@@ -315,7 +315,7 @@ module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
#endif
bool is_manager_apk(char *path)
bool ksu_is_manager_apk(char *path)
{
int tries = 0;

View File

@@ -3,6 +3,6 @@
#include <linux/types.h>
bool is_manager_apk(char *path);
bool ksu_is_manager_apk(char *path);
#endif

View File

@@ -35,6 +35,10 @@
#include <linux/vmalloc.h>
#endif
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif // #ifdef CONFIG_KSU_SUSFS
#include "allowlist.h"
#include "arch.h"
#include "core_hook.h"
@@ -44,20 +48,91 @@
#include "manager.h"
#include "selinux/selinux.h"
#include "throne_tracker.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 handle_sepolicy(unsigned long arg3, void __user *arg4);
extern int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4);
static bool ksu_su_compat_enabled = true;
bool ksu_su_compat_enabled = true;
extern void ksu_sucompat_init();
extern void ksu_sucompat_exit();
static inline bool is_allow_su()
{
if (is_manager()) {
if (ksu_is_manager()) {
// we are manager, allow!
return true;
}
@@ -135,7 +210,7 @@ static void disable_seccomp(void)
#endif
}
void escape_to_root(void)
void ksu_escape_to_root(void)
{
struct cred *cred;
@@ -193,7 +268,7 @@ void escape_to_root(void)
disable_seccomp();
spin_unlock_irq(&current->sighand->siglock);
setup_selinux(profile->selinux_domain);
ksu_setup_selinux(profile->selinux_domain);
}
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
@@ -230,7 +305,7 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname,
new_dentry->d_iname, buf);
track_throne();
ksu_track_throne();
return 0;
}
@@ -275,7 +350,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
bool from_root = 0 == current_uid().val;
bool from_manager = is_manager();
bool from_manager = ksu_is_manager();
if (!from_root && !from_manager) {
// only root or manager can access this interface
@@ -299,7 +374,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (arg2 == CMD_GRANT_ROOT) {
if (is_allow_su()) {
pr_info("allow root for: %d\n", current_uid().val);
escape_to_root();
ksu_escape_to_root();
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("grant_root: prctl reply error\n");
}
@@ -354,10 +429,13 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
switch (arg3) {
case EVENT_POST_FS_DATA: {
static bool post_fs_data_lock = false;
#ifdef CONFIG_KSU_SUSFS
susfs_on_post_fs_data();
#endif
if (!post_fs_data_lock) {
post_fs_data_lock = true;
pr_info("post-fs-data triggered\n");
on_post_fs_data();
ksu_on_post_fs_data();
}
break;
}
@@ -385,7 +463,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (!from_root) {
return 0;
}
if (!handle_sepolicy(arg3, arg4)) {
if (!ksu_handle_sepolicy(arg3, arg4)) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("sepolicy: prctl reply error\n");
}
@@ -446,6 +524,352 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
#ifdef CONFIG_KSU_SUSFS
if (current_uid_val == 0) {
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
if (arg2 == CMD_SUSFS_ADD_SUS_PATH) {
int error = 0;
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_path))) {
pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH -> arg3 is not accessible\n");
return 0;
}
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH -> arg5 is not accessible\n");
return 0;
}
error = susfs_add_sus_path((struct st_susfs_sus_path __user*)arg3);
pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH -> ret: %d\n", error);
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
pr_info("susfs: copy_to_user() failed\n");
return 0;
}
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;
@@ -511,6 +935,12 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
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();
@@ -549,11 +979,15 @@ static bool should_umount(struct path *path)
return false;
}
#ifdef CONFIG_KSU_SUSFS
return susfs_is_mnt_devname_ksu(path);
#else
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
const char *fstype = path->mnt->mnt_sb->s_type->name;
return strcmp(fstype, "overlay") == 0;
}
return false;
#endif
}
static int ksu_umount_mnt(struct path *path, int flags)
@@ -566,7 +1000,11 @@ static int ksu_umount_mnt(struct path *path, int flags)
#endif
}
static void try_umount(const char *mnt, bool check_mnt, int flags)
#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);
@@ -586,12 +1024,45 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
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", true, 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!
@@ -611,6 +1082,52 @@ 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);
#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;
@@ -620,7 +1137,20 @@ 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 {
@@ -629,10 +1159,12 @@ 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 = is_zygote(old->security);
bool is_zygote_child = ksu_is_zygote(old->security);
#endif
if (!is_zygote_child) {
pr_info("handle umount ignore non zygote child: %d\n",
current->pid);
@@ -644,25 +1176,31 @@ 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`
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);
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
try_umount("/debug_ramdisk", false, MNT_DETACH);
try_umount("/sbin", false, MNT_DETACH);
ksu_try_umount("/debug_ramdisk", false, MNT_DETACH);
ksu_try_umount("/sbin", false, MNT_DETACH);
// try umount hosts file
try_umount("/system/etc/hosts", false, MNT_DETACH);
ksu_try_umount("/system/etc/hosts", false, MNT_DETACH);
// 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);
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;
}

View File

@@ -76,6 +76,16 @@ void ksu_android_ns_fs_check()
task_unlock(current);
}
int ksu_access_ok(const void *addr, unsigned long size) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
/* For kernels before 5.0.0, pass the type argument to access_ok. */
return access_ok(VERIFY_READ, addr, size);
#else
/* For kernels 5.0.0 and later, ignore the type argument. */
return access_ok(addr, size);
#endif
}
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
@@ -174,15 +184,6 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
}
#endif
static inline int ksu_access_ok(const void *addr, unsigned long size)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
return access_ok(addr, size);
#else
return access_ok(VERIFY_READ, addr, size);
#endif
}
long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr,
long count)
{

View File

@@ -32,6 +32,7 @@ extern struct key *init_session_keyring;
#endif
extern void ksu_android_ns_fs_check();
extern int ksu_access_ok(const void *addr, unsigned long size);
extern struct file *ksu_filp_open_compat(const char *filename, int flags,
umode_t mode);
extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,

View File

@@ -11,6 +11,10 @@
#include "ksu.h"
#include "throne_tracker.h"
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
static struct workqueue_struct *ksu_workqueue;
bool ksu_queue_work(struct work_struct *work)
@@ -37,7 +41,7 @@ extern void ksu_sucompat_exit();
extern void ksu_ksud_init();
extern void ksu_ksud_exit();
int __init kernelsu_init(void)
int __init ksu_kernelsu_init(void)
{
#ifdef CONFIG_KSU_DEBUG
pr_alert("*************************************************************");
@@ -49,6 +53,10 @@ int __init kernelsu_init(void)
pr_alert("*************************************************************");
#endif
#ifdef CONFIG_KSU_SUSFS
susfs_init();
#endif
ksu_core_init();
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
@@ -72,7 +80,7 @@ int __init kernelsu_init(void)
return 0;
}
void kernelsu_exit(void)
void ksu_kernelsu_exit(void)
{
ksu_allowlist_exit();
@@ -88,8 +96,8 @@ void kernelsu_exit(void)
ksu_core_exit();
}
module_init(kernelsu_init);
module_exit(kernelsu_exit);
module_init(ksu_kernelsu_init);
module_exit(ksu_kernelsu_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("weishu");

View File

@@ -64,6 +64,9 @@ bool ksu_vfs_read_hook __read_mostly = true;
bool ksu_execveat_hook __read_mostly = true;
bool ksu_input_hook __read_mostly = true;
#ifdef CONFIG_KSU_SUSFS_SUS_SU
bool susfs_is_sus_su_ready = false;
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
u32 ksu_devpts_sid;
@@ -71,15 +74,15 @@ u32 ksu_devpts_sid;
bool ksu_is_compat __read_mostly = false;
#endif
void on_post_fs_data(void)
void ksu_on_post_fs_data(void)
{
static bool done = false;
if (done) {
pr_info("on_post_fs_data already done\n");
pr_info("ksu_on_post_fs_data already done\n");
return;
}
done = true;
pr_info("on_post_fs_data!\n");
pr_info("ksu_on_post_fs_data!\n");
ksu_load_allow_list();
// sanity check, this may influence the performance
stop_input_hook();
@@ -203,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");
apply_kernelsu_rules();
ksu_apply_kernelsu_rules();
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
@@ -227,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");
apply_kernelsu_rules();
ksu_apply_kernelsu_rules();
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
@@ -264,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");
apply_kernelsu_rules();
ksu_apply_kernelsu_rules();
init_second_stage_executed =
true;
ksu_android_ns_fs_check();
@@ -279,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);
on_post_fs_data(); // we keep this for old ksud
ksu_on_post_fs_data(); // we keep this for old ksud
stop_execve_hook();
}
@@ -677,6 +680,10 @@ static void stop_execve_hook()
ksu_execveat_hook = false;
pr_info("stop execve_hook\n");
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_SU
susfs_is_sus_su_ready = true;
pr_info("susfs: sus_su is ready\n");
#endif
}
static void stop_input_hook()

View File

@@ -5,7 +5,7 @@
#define KSUD_PATH "/data/adb/ksud"
void on_post_fs_data(void);
void ksu_on_post_fs_data(void);
bool ksu_is_safe_mode(void);

View File

@@ -13,7 +13,7 @@ static inline bool ksu_is_manager_uid_valid()
return ksu_manager_uid != KSU_INVALID_UID;
}
static inline bool is_manager()
static inline bool ksu_is_manager()
{
return unlikely(ksu_manager_uid == current_uid().val);
}

View File

@@ -38,11 +38,11 @@ static struct policydb *get_policydb(void)
static DEFINE_MUTEX(ksu_rules);
void apply_kernelsu_rules()
void ksu_apply_kernelsu_rules()
{
struct policydb *db;
if (!getenforce()) {
if (!ksu_getenforce()) {
pr_info("SELinux permissive or disabled, apply rules!\n");
}
@@ -139,6 +139,14 @@ void apply_kernelsu_rules()
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
#ifdef CONFIG_KSU_SUSFS
// Allow umount in zygote process without installing zygisk
ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount");
susfs_set_init_sid();
susfs_set_ksu_sid();
susfs_set_zygote_sid();
#endif
mutex_unlock(&ksu_rules);
}
@@ -228,13 +236,13 @@ static void reset_avc_cache()
selinux_xfrm_notify_policyload();
}
int handle_sepolicy(unsigned long arg3, void __user *arg4)
int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4)
{
if (!arg4) {
return -1;
}
if (!getenforce()) {
if (!ksu_getenforce()) {
pr_info("SELinux permissive or disabled when handle policy!\n");
}

View File

@@ -8,6 +8,14 @@
#define KERNEL_SU_DOMAIN "u:r:su:s0"
#ifdef CONFIG_KSU_SUSFS
#define KERNEL_INIT_DOMAIN "u:r:init:s0"
#define KERNEL_ZYGOTE_DOMAIN "u:r:zygote:s0"
u32 susfs_ksu_sid = 0;
u32 susfs_init_sid = 0;
u32 susfs_zygote_sid = 0;
#endif
static int transive_to_domain(const char *domain)
{
struct cred *cred;
@@ -37,7 +45,7 @@ static int transive_to_domain(const char *domain)
return error;
}
void setup_selinux(const char *domain)
void ksu_setup_selinux(const char *domain)
{
if (transive_to_domain(domain)) {
pr_err("transive domain failed.\n");
@@ -52,7 +60,7 @@ if (!is_domain_permissive) {
}*/
}
void setenforce(bool enforce)
void ksu_setenforce(bool enforce)
{
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
#ifdef KSU_COMPAT_USE_SELINUX_STATE
@@ -63,7 +71,7 @@ void setenforce(bool enforce)
#endif
}
bool getenforce()
bool ksu_getenforce()
{
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
#ifdef KSU_COMPAT_USE_SELINUX_STATE
@@ -99,7 +107,7 @@ static inline u32 current_sid(void)
}
#endif
bool is_ksu_domain()
bool ksu_is_ksu_domain()
{
char *domain;
u32 seclen;
@@ -113,7 +121,7 @@ bool is_ksu_domain()
return result;
}
bool is_zygote(void *sec)
bool ksu_is_zygote(void *sec)
{
struct task_security_struct *tsec = (struct task_security_struct *)sec;
if (!tsec) {
@@ -131,6 +139,83 @@ bool is_zygote(void *sec)
return result;
}
#ifdef CONFIG_KSU_SUSFS
static inline void susfs_set_sid(const char *secctx_name, u32 *out_sid)
{
int err;
if (!secctx_name || !out_sid) {
pr_err("secctx_name || out_sid is NULL\n");
return;
}
err = security_secctx_to_secid(secctx_name, strlen(secctx_name),
out_sid);
if (err) {
pr_err("failed setting sid for '%s', err: %d\n", secctx_name, err);
return;
}
pr_info("sid '%u' is set for secctx_name '%s'\n", *out_sid, secctx_name);
}
bool susfs_is_sid_equal(void *sec, u32 sid2) {
struct task_security_struct *tsec = (struct task_security_struct *)sec;
if (!tsec) {
return false;
}
return tsec->sid == sid2;
}
u32 susfs_get_sid_from_name(const char *secctx_name)
{
u32 out_sid = 0;
int err;
if (!secctx_name) {
pr_err("secctx_name is NULL\n");
return 0;
}
err = security_secctx_to_secid(secctx_name, strlen(secctx_name),
&out_sid);
if (err) {
pr_err("failed getting sid from secctx_name: %s, err: %d\n", secctx_name, err);
return 0;
}
return out_sid;
}
u32 susfs_get_current_sid(void) {
return current_sid();
}
void susfs_set_zygote_sid(void)
{
susfs_set_sid(KERNEL_ZYGOTE_DOMAIN, &susfs_zygote_sid);
}
bool susfs_is_current_zygote_domain(void) {
return unlikely(current_sid() == susfs_zygote_sid);
}
void susfs_set_ksu_sid(void)
{
susfs_set_sid(KERNEL_SU_DOMAIN, &susfs_ksu_sid);
}
bool susfs_is_current_ksu_domain(void) {
return unlikely(current_sid() == susfs_ksu_sid);
}
void susfs_set_init_sid(void)
{
susfs_set_sid(KERNEL_INIT_DOMAIN, &susfs_init_sid);
}
bool susfs_is_current_init_domain(void) {
return unlikely(current_sid() == susfs_init_sid);
}
#endif
#define DEVPTS_DOMAIN "u:object_r:ksu_file:s0"
u32 ksu_get_devpts_sid()

View File

@@ -8,17 +8,29 @@
#define KSU_COMPAT_USE_SELINUX_STATE
#endif
void setup_selinux(const char *);
void ksu_setup_selinux(const char *);
void setenforce(bool);
void ksu_setenforce(bool);
bool getenforce();
bool ksu_getenforce();
bool is_ksu_domain();
bool ksu_is_ksu_domain();
bool is_zygote(void *cred);
bool ksu_is_zygote(void *cred);
void apply_kernelsu_rules();
void ksu_apply_kernelsu_rules();
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
bool susfs_is_sid_equal(void *sec, u32 sid2);
u32 susfs_get_sid_from_name(const char *secctx_name);
u32 susfs_get_current_sid(void);
void susfs_set_zygote_sid(void);
bool susfs_is_current_zygote_domain(void);
void susfs_set_ksu_sid(void);
bool susfs_is_current_ksu_domain(void);
void susfs_set_init_sid(void);
bool susfs_is_current_init_domain(void);
#endif
u32 ksu_get_devpts_sid();

View File

@@ -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 && echo "[-] Switched to next branch."
git checkout next-susfs-a13-5.15-dev && echo "[-] Switched to next-susfs-a13-5.15-dev branch."
fi
git pull && echo "[+] Repository updated."
if [ -z "${1-}" ]; then

View File

@@ -13,6 +13,9 @@
#else
#include <linux/sched.h>
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_SU
#include <linux/susfs_def.h>
#endif
#include "objsec.h"
#include "allowlist.h"
@@ -28,9 +31,13 @@
static bool ksu_sucompat_non_kp __read_mostly = true;
#endif
extern void escape_to_root();
extern void ksu_escape_to_root();
static void __user *userspace_stack_buffer(const void *d, size_t len)
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. */
@@ -39,37 +46,37 @@ static void __user *userspace_stack_buffer(const void *d, size_t len)
return copy_to_user(p, d, len) ? NULL : p;
}
static char __user *sh_user_path(void)
static inline char __user *sh_user_path(void)
{
static const char sh_path[] = "/system/bin/sh";
return userspace_stack_buffer(sh_path, sizeof(sh_path));
}
static char __user *ksud_user_path(void)
static inline char __user *ksud_user_path(void)
{
static const char ksud_path[] = KSUD_PATH;
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)
{
const char su[] = SU_PATH;
#ifndef CONFIG_KSU_KPROBES_HOOK
if (!ksu_sucompat_non_kp) {
return 0;
}
#endif
if (!ksu_is_allow_uid(current_uid().val)) {
return 0;
}
#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)))) {
@@ -80,27 +87,49 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS_SUS_SU)
struct filename* susfs_ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) {
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)
{
// const char sh[] = SH_PATH;
const char su[] = SU_PATH;
#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
@@ -132,8 +161,6 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
int *__never_use_flags)
{
struct filename *filename;
const char sh[] = KSUD_PATH;
const char su[] = SU_PATH;
#ifndef CONFIG_KSU_KPROBES_HOOK
if (!ksu_sucompat_non_kp) {
@@ -152,13 +179,15 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
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, sh, sizeof(sh));
memcpy((void *)filename->name, ksud_path, sizeof(ksud_path));
escape_to_root();
ksu_escape_to_root();
return 0;
}
@@ -167,8 +196,11 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
void *__never_use_argv, void *__never_use_envp,
int *__never_use_flags)
{
const char su[] = SU_PATH;
#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) {
@@ -206,7 +238,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
pr_info("sys_execve su found\n");
*filename_user = ksud_user_path();
escape_to_root();
ksu_escape_to_root();
return 0;
}
@@ -352,3 +384,41 @@ void ksu_sucompat_exit()
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

View File

@@ -192,7 +192,7 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
}
}
bool is_manager = is_manager_apk(dirpath);
bool is_manager = ksu_is_manager_apk(dirpath);
pr_info("Found new base.apk at path: %s, is_manager: %d\n",
dirpath, is_manager);
if (is_manager) {
@@ -351,7 +351,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
return exist;
}
void track_throne()
void ksu_track_throne()
{
struct file *fp;
int tries = 0;

View File

@@ -5,7 +5,7 @@ void ksu_throne_tracker_init();
void ksu_throne_tracker_exit();
void track_throne();
void ksu_track_throne();
bool is_lock_held(const char *path);