kernel: Apply the susfs patch

Co-authored-by: simonpunk <simonpunk2016@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-11-14 18:36:04 +08:00
parent 4920877dd8
commit 4c04508267
20 changed files with 982 additions and 77 deletions

View File

@@ -48,4 +48,131 @@ config KSU_MANUAL_HOOK
help
If enabled, Hook required KernelSU syscalls with manually-patched function.
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_SUS_PATH
bool "Enable to hide suspicious path (NOT recommended)"
depends on KSU_SUSFS
default n
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 n
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 try_umount"
depends on KSU_SUSFS
default y
help
- 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 try_umount automatically (experimental)"
depends on KSU_SUSFS_TRY_UMOUNT
default y
help
- 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.
config KSU_SUSFS_SPOOF_UNAME
bool "Enable to spoof uname"
depends on KSU_SUSFS
default n
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 n
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_MAP
bool "Enable to hide some mmapped real file from different proc maps interfaces"
depends on KSU_SUSFS
default y
help
- Allow hiding mmapped real file from /proc/<pid>/[maps|smaps|smaps_rollup|map_files|mem|pagemap]
- It does NOT support hiding for anon memory.
- It does NOT hide any inline hooks or plt hooks cause by the injected library itself.
- It may not be able to evade detections by apps that implement a good injection detection.
- Effective only on zygote spawned umounted user app process.
endmenu
endmenu

View File

@@ -18,6 +18,7 @@ kernelsu-objs += seccomp_cache.o
kernelsu-objs += file_wrapper.o
kernelsu-objs += throne_comm.o
kernelsu-objs += sulog.o
kernelsu-objs += lsm_hook.o
ifeq ($(CONFIG_KSU_MANUAL_SU), y)
ccflags-y += -DCONFIG_KSU_MANUAL_SU
@@ -183,4 +184,14 @@ $(info -- Supported Unofficial Manager: 5ec1cff (GKI) rsuntk (Non-GKI) ShirkNeko
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable
## 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 integrated susfs in your kernel yet.)
$(info -- Read: https://gitlab.com/simonpunk/susfs4ksu)
endif
# Keep a new line here!! Because someone may append config

View File

@@ -21,7 +21,9 @@
#include "selinux/selinux.h"
#include "allowlist.h"
#include "manager.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif // #ifndef CONFIG_KSU_SUSFS
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 3 // u32
@@ -262,8 +264,10 @@ out:
if (persist) {
persistent_allow_list();
#ifndef CONFIG_KSU_SUSFS
// FIXME: use a new flag
ksu_mark_running_process();
#endif // #ifndef CONFIG_KSU_SUSFS
}
return result;

View File

@@ -12,7 +12,9 @@
#include "app_profile.h"
#include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif
#include "sucompat.h"
#include "sulog.h"
@@ -88,8 +90,10 @@ void disable_seccomp(void)
void escape_with_root_profile(void)
{
struct cred *cred;
#ifndef CONFIG_KSU_SUSFS
struct task_struct *p = current;
struct task_struct *t;
#endif
cred = prepare_creds();
if (!cred) {
@@ -149,9 +153,11 @@ void escape_with_root_profile(void)
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root");
#endif
#ifndef CONFIG_KSU_SUSFS
for_each_thread (p, t) {
ksu_set_task_tracepoint_flag(t);
}
#endif
}
#ifdef CONFIG_KSU_MANUAL_SU
@@ -214,9 +220,10 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
{
struct cred *newcreds;
struct task_struct *target_task;
unsigned long flags;
#ifndef CONFIG_KSU_SUSFS
struct task_struct *p = current;
struct task_struct *t;
#endif
pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid);
@@ -298,9 +305,11 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
#if __SULOG_GATE
ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation");
#endif
#ifndef CONFIG_KSU_SUSFS
for_each_thread (p, t) {
ksu_set_task_tracepoint_flag(t);
}
#endif
pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid);
}
#endif

View File

@@ -21,7 +21,11 @@
#include "sulog.h"
#ifndef CONFIG_KSU_SUSFS
static bool ksu_kernel_umount_enabled = true;
#else
bool ksu_kernel_umount_enabled = true;
#endif
static int kernel_umount_feature_get(u64 *value)
{
@@ -44,11 +48,25 @@ static const struct ksu_feature_handler kernel_umount_handler = {
.set_handler = kernel_umount_feature_set,
};
#ifdef CONFIG_KSU_SUSFS
extern bool susfs_is_mnt_devname_ksu(struct path *path);
#if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG)
extern bool susfs_is_log_enabled;
#endif // #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG)
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
extern void susfs_try_umount(void);
#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
#endif // #ifdef CONFIG_KSU_SUSFS
static bool should_umount(struct path *path)
{
if (!path) {
return false;
}
#ifdef CONFIG_KSU_SUSFS
return susfs_is_mnt_devname_ksu(path);
#else
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
pr_info("ignore global mnt namespace process: %d\n", current_uid().val);
@@ -60,6 +78,7 @@ static bool should_umount(struct path *path)
return strcmp(fstype, "overlay") == 0;
}
return false;
#endif // #ifdef CONFIG_KSU_SUSFS
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT)
@@ -97,7 +116,11 @@ static int ksu_sys_umount(const char *mnt, int flags)
})
#endif
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
void try_umount(const char *mnt, bool check_mnt, int flags)
#else
static void try_umount(const char *mnt, bool check_mnt, int flags)
#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
{
struct path path;
int ret;
@@ -118,6 +141,12 @@ 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'\n", mnt);
}
#endif // #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG)
ret = ksu_umount_mnt(mnt, &path, flags);
if (ret) {
#ifdef CONFIG_KSU_DEBUG
@@ -126,6 +155,20 @@ void try_umount(const char *mnt, bool check_mnt, int flags)
}
}
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
void susfs_try_umount_all(void) {
susfs_try_umount();
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("/debug_ramdisk", true, MNT_DETACH);
}
#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
#ifndef CONFIG_KSU_SUSFS
struct umount_tw {
struct callback_head cb;
const struct cred *old_cred;
@@ -147,15 +190,8 @@ static void umount_tw_func(struct callback_head *cb)
try_umount("/product", true, 0);
try_umount("/system_ext", true, 0);
try_umount("/data/adb/modules", false, MNT_DETACH);
try_umount("/data/adb/kpm", false, MNT_DETACH);
// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
try_umount("/sbin", false, MNT_DETACH);
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);
if (saved)
revert_creds(saved);
@@ -224,6 +260,7 @@ int ksu_handle_umount(uid_t old_uid, uid_t new_uid)
return 0;
}
#endif // #ifndef CONFIG_KSU_SUSFS
void ksu_kernel_umount_init(void)
{

View File

@@ -6,7 +6,9 @@
void ksu_kernel_umount_init(void);
void ksu_kernel_umount_exit(void);
#ifndef CONFIG_KSU_SUSFS
// Handler function to be called from setresuid hook
int ksu_handle_umount(uid_t old_uid, uid_t new_uid);
#endif // #ifndef CONFIG_KSU_SUSFS
#endif

View File

@@ -7,11 +7,18 @@
#include <generated/compile.h>
#include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION macros */
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
#include "allowlist.h"
#include "ksu.h"
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include "throne_tracker.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif
#include "ksud.h"
#include "supercalls.h"
@@ -57,11 +64,15 @@ int __init kernelsu_init(void)
ksu_feature_init();
ksu_lsm_hook_init();
ksu_supercalls_init();
sukisu_custom_config_init();
#if defined(CONFIG_KPROBES) && !defined(CONFIG_KSU_SUSFS)
ksu_syscall_hook_manager_init();
#endif
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
@@ -69,7 +80,13 @@ int __init kernelsu_init(void)
ksu_throne_tracker_init();
#ifdef CONFIG_KSU_SUSFS
susfs_init();
#endif
#if defined(CONFIG_KPROBES) && !defined(CONFIG_KSU_SUSFS)
ksu_ksud_init();
#endif
#ifdef MODULE
#ifndef CONFIG_KSU_DEBUG
@@ -90,9 +107,11 @@ void kernelsu_exit(void)
destroy_workqueue(ksu_workqueue);
#if defined(CONFIG_KPROBES) && !defined(CONFIG_KSU_SUSFS)
ksu_ksud_exit();
ksu_syscall_hook_manager_exit();
#endif
sukisu_custom_config_exit();

View File

@@ -43,6 +43,8 @@ struct manager_list_info {
bool ksu_queue_work(struct work_struct *work);
void ksu_lsm_hook_init(void);
#if 0
static inline int startswith(char *s, char *prefix)
{

View File

@@ -33,7 +33,9 @@
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "selinux/selinux.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif // #ifndef CONFIG_KSU_SUSFS
bool ksu_module_mounted __read_mostly = false;
bool ksu_boot_completed __read_mostly = false;
@@ -65,7 +67,7 @@ static void stop_vfs_read_hook(void);
static void stop_execve_hook(void);
static void stop_input_hook(void);
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
static struct work_struct stop_vfs_read_work;
static struct work_struct stop_execve_hook_work;
static struct work_struct stop_input_hook_work;
@@ -90,8 +92,10 @@ void on_post_fs_data(void)
done = true;
pr_info("on_post_fs_data!\n");
ksu_load_allow_list();
#ifndef CONFIG_KSU_SUSFS
pr_info("mark tif for running process\n");
ksu_mark_running_process();
#endif // #ifndef CONFIG_KSU_SUSFS
ksu_observer_init();
// sanity check, this may influence the performance
stop_input_hook();
@@ -136,11 +140,15 @@ void on_module_mounted(void){
void on_boot_completed(void){
ksu_boot_completed = true;
pr_info("on_boot_completed!\n");
#ifndef CONFIG_KSU_SUSFS
// remark process, we don't want to mark other init
// forked process excepte zygote and adbd
ksu_unmark_all_process();
ksu_mark_running_process();
#endif // #ifndef CONFIG_KSU_SUSFS
}
#ifndef CONFIG_KSU_SUSFS
#define MAX_ARG_STRINGS 0x7FFFFFFF
struct user_arg_ptr {
#ifdef CONFIG_COMPAT
@@ -153,6 +161,7 @@ struct user_arg_ptr {
#endif
} ptr;
};
#endif // #ifndef CONFIG_KSU_SUSFS
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
@@ -335,7 +344,9 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
task_work_add(init_task, &on_post_fs_data_cb, TWA_RESUME);
}
rcu_read_unlock();
#ifndef CONFIG_KSU_SUSFS
ksu_set_task_tracepoint_flag(current); // we are zygote!
#endif
stop_execve_hook();
}
@@ -529,7 +540,7 @@ bool ksu_is_safe_mode()
return false;
}
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
@@ -605,7 +616,7 @@ static void do_stop_input_hook(struct work_struct *work)
static void stop_vfs_read_hook(void)
{
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
bool ret = schedule_work(&stop_vfs_read_work);
pr_info("unregister vfs_read kprobe: %d!\n", ret);
#else
@@ -616,7 +627,7 @@ static void stop_vfs_read_hook(void)
static void stop_execve_hook(void)
{
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
bool ret = schedule_work(&stop_execve_hook_work);
pr_info("unregister execve kprobe: %d!\n", ret);
#else
@@ -632,7 +643,7 @@ static void stop_input_hook(void)
return;
}
input_hook_stopped = true;
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
bool ret = schedule_work(&stop_input_hook_work);
pr_info("unregister input kprobe: %d!\n", ret);
#else
@@ -644,7 +655,7 @@ static void stop_input_hook(void)
// ksud: module support
void ksu_ksud_init(void)
{
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
int ret;
ret = register_kprobe(&execve_kp);
@@ -664,7 +675,7 @@ void ksu_ksud_init(void)
void ksu_ksud_exit(void)
{
#ifdef KSU_KPROBES_HOOK
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
unregister_kprobe(&execve_kp);
// this should be done before unregister vfs_read_kp
// unregister_kprobe(&vfs_read_kp);

View File

@@ -18,4 +18,23 @@ extern u32 ksu_file_sid;
extern bool ksu_module_mounted;
extern bool ksu_boot_completed;
#ifdef CONFIG_KSU_SUSFS
#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;
};
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
struct user_arg_ptr *argv,
struct user_arg_ptr *envp, int *flags);
#endif // #ifdef CONFIG_KSU_SUSFS
#endif

74
kernel/lsm_hook.c Normal file
View File

@@ -0,0 +1,74 @@
#include <linux/version.h>
#include <linux/security.h>
#include <linux/lsm_hooks.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/key.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/uidgid.h>
#include "kernel_compat.h"
#include "ksu.h"
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0) && defined(CONFIG_KSU_MANUAL_SU)
#include "manual_su.h"
static int ksu_task_alloc(struct task_struct *task,
unsigned long clone_flags)
{
ksu_try_escalate_for_uid(task_uid(task).val);
return 0;
}
#endif
// kernel 4.4 and 4.9
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
defined(CONFIG_IS_HW_HISI) || \
defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
static 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
static struct security_hook_list ksu_hooks[] = {
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0) && defined(CONFIG_KSU_MANUAL_SU)
LSM_HOOK_INIT(task_alloc, ksu_task_alloc),
#endif
#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
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
const struct lsm_id ksu_lsmid = {
.name = "ksu",
.id = 912,
};
#endif
void __init ksu_lsm_hook_init(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
// https://elixir.bootlin.com/linux/v6.8/source/include/linux/lsm_hooks.h#L120
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), &ksu_lsmid);
#elif 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
}

View File

@@ -18,21 +18,36 @@ static inline bool ksu_is_manager_uid_valid(void)
return ksu_manager_uid != KSU_INVALID_UID;
}
#ifndef CONFIG_KSU_SUSFS
static inline bool is_manager(void)
{
return unlikely(ksu_is_any_manager(current_uid().val) ||
(ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val));
}
#else
static inline bool is_manager()
{
return unlikely((ksu_manager_uid == current_uid().val % 100000) ||
(ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val % 100000));
}
#endif
static inline uid_t ksu_get_manager_uid(void)
{
return ksu_manager_uid;
}
#ifndef CONFIG_KSU_SUSFS
static inline void ksu_set_manager_uid(uid_t uid)
{
ksu_manager_uid = uid;
}
#else
static inline void ksu_set_manager_uid(uid_t uid)
{
ksu_manager_uid = uid % 100000;
}
#endif
static inline void ksu_invalidate_manager_uid(void)
{

View File

@@ -142,6 +142,15 @@ void apply_kernelsu_rules(void)
// https://android-review.googlesource.com/c/platform/system/logging/+/3725346
ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr");
#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();
#endif
mutex_unlock(&ksu_rules);
}

View File

@@ -166,3 +166,96 @@ u32 ksu_get_ksu_file_sid()
}
return ksu_file_sid;
}
#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"
#ifndef KERNEL_SU_DOMAIN
#define KERNEL_SU_DOMAIN "u:r:su:s0"
#endif // #ifndef KERNEL_SU_DOMAIN
u32 susfs_ksu_sid = 0;
u32 susfs_init_sid = 0;
u32 susfs_zygote_sid = 0;
u32 susfs_kernel_sid = 0;
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);
}
void susfs_set_kernel_sid(void)
{
susfs_set_sid(KERNEL_KERNEL_DOMAIN, &susfs_kernel_sid);
}
#endif

View File

@@ -29,4 +29,17 @@ u32 ksu_get_ksu_file_sid(void);
int handle_sepolicy(unsigned long arg3, void __user *arg4);
#ifdef CONFIG_KSU_SUSFS
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);
void susfs_set_kernel_sid(void);
#endif // #ifdef CONFIG_KSU_SUSFS
#endif

View File

@@ -29,10 +29,13 @@
#include <linux/uaccess.h>
#include <linux/uidgid.h>
#include <linux/version.h>
#include <linux/lsm_hooks.h>
#include <linux/binfmts.h>
#include <linux/tty.h>
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif // #ifdef CONFIG_KSU_SUSFS
#ifndef KSU_HAS_PATH_UMOUNT
#include <linux/syscalls.h> // sys_umount (<4.17) & ksys_umount (4.17+)
#endif
@@ -54,12 +57,48 @@
#include "selinux/selinux.h"
#include "seccomp_cache.h"
#include "supercalls.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif
#include "kernel_umount.h"
#include "app_profile.h"
#include "sulog.h"
#ifdef CONFIG_KSU_SUSFS
static inline bool is_some_system_uid(uid_t uid)
{
uid %= 100000;
return (uid >= 1000 && uid < 10000);
}
static inline bool is_zygote_isolated_service_uid(uid_t uid)
{
uid %= 100000;
return (uid >= 90000 && uid < 100000);
}
static inline bool is_zygote_normal_app_uid(uid_t uid)
{
uid %= 100000;
return (uid >= 10000 && uid < 19999);
}
bool susfs_is_umount_for_zygote_system_process_enabled = false;
extern bool susfs_is_umount_for_zygote_iso_service_enabled;
extern u32 susfs_zygote_sid;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
extern void susfs_run_sus_path_loop(uid_t uid);
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
extern void susfs_reorder_mnt_id(void);
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
extern void susfs_try_umount_all(void);
#endif
#endif // #ifdef CONFIG_KSU_SUSFS
static bool ksu_enhanced_security_enabled = false;
static int enhanced_security_feature_get(u64 *value)
@@ -92,6 +131,7 @@ static inline bool is_allow_su(void)
return ksu_is_allow_uid_for_current(current_uid().val);
}
#ifndef CONFIG_KSU_SUSFS
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid)
{
uid_t new_uid = ruid;
@@ -171,59 +211,114 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid)
return 0;
}
// kernel 4.4 and 4.9
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
defined(CONFIG_IS_HW_HISI) || \
defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
static 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
#ifndef MODULE
static struct security_hook_list ksu_hooks[] = {
#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
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
const struct lsm_id ksu_lsmid = {
.name = "ksu",
.id = 912,
};
#endif
void __init ksu_lsm_hook_init(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
// https://elixir.bootlin.com/linux/v6.8/source/include/linux/lsm_hooks.h#L120
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), &ksu_lsmid);
#elif 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
extern bool ksu_kernel_umount_enabled;
extern bool ksu_module_mounted;
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid){
// we rely on the fact that zygote always call setresuid(3) with same uids
uid_t new_uid = ruid;
uid_t old_uid = current_uid().val;
// if old process is root, ignore it.
if (old_uid != 0 && ksu_enhanced_security_enabled) {
// disallow any non-ksu domain escalation from non-root to root!
// euid is what we care about here as it controls permission
if (unlikely(euid == 0)) {
if (!is_ksu_domain()) {
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
current->pid, current->comm, old_uid, new_uid);
force_sig(SIGKILL);
return 0;
}
#endif
}
// disallow appuid decrease to any other uid if it is not allowed to su
if (is_appuid(old_uid)) {
if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) {
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
current->pid, current->comm, old_uid, new_uid);
force_sig(SIGKILL);
return 0;
}
}
return 0;
}
// We only interest in process spwaned by zygote
if (!susfs_is_sid_equal(current_cred()->security, susfs_zygote_sid)) {
return 0;
}
// Check if spawned process is isolated service first, and force to do umount if so
if (is_zygote_isolated_service_uid(new_uid) && susfs_is_umount_for_zygote_iso_service_enabled) {
goto do_umount;
}
// - Since ksu maanger app uid is excluded in allow_list_arr, so ksu_uid_should_umount(manager_uid)
// will always return true, that's why we need to explicitly check if new_uid belongs to
// ksu manager
if (ksu_get_manager_uid() == new_uid % 100000) {
pr_info("install fd for manager: %d\n", new_uid);
ksu_install_fd();
spin_lock_irq(&current->sighand->siglock);
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot);
spin_unlock_irq(&current->sighand->siglock);
return 0;
}
// Check if spawned process is normal user app and needs to be umounted
if (likely(is_zygote_normal_app_uid(new_uid) && ksu_uid_should_umount(new_uid))) {
goto do_umount;
}
// Lastly, Check if spawned process is some system process and needs to be umounted
if (unlikely(is_some_system_uid(new_uid) && susfs_is_umount_for_zygote_system_process_enabled)) {
goto do_umount;
}
if (ksu_is_allow_uid_for_current(new_uid)) {
if (current->seccomp.mode == SECCOMP_MODE_FILTER &&
current->seccomp.filter) {
spin_lock_irq(&current->sighand->siglock);
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot);
spin_unlock_irq(&current->sighand->siglock);
}
}
return 0;
do_umount:
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
if (!ksu_kernel_umount_enabled || !ksu_module_mounted) {
goto skip_try_umount;
}
pr_info("susfs: running susfs_try_umount_all() for uid: %u\n", new_uid);
susfs_try_umount_all();
skip_try_umount:
#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
get_task_struct(current);
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// We can reorder the mnt_id now after all sus mounts are umounted
susfs_reorder_mnt_id();
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
susfs_set_current_proc_umounted();
put_task_struct(current);
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
susfs_run_sus_path_loop(new_uid);
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_PATH
return 0;
}
#endif // #ifndef CONFIG_KSU_SUSFS
void ksu_setuid_hook_init(void)
{
ksu_lsm_hook_init();
ksu_kernel_umount_init();
if (ksu_register_feature_handler(&enhanced_security_handler)) {
pr_err("Failed to register enhanced security feature handler\n");

View File

@@ -13,13 +13,20 @@
#include <linux/sched.h>
#endif
#ifdef CONFIG_KSU_SUSFS
#include <linux/namei.h>
#include "objsec.h"
#endif // #ifdef CONFIG_KSU_SUSFS
#include "allowlist.h"
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "sucompat.h"
#include "app_profile.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif // #ifndef CONFIG_KSU_SUSFS
#include "sulog.h"
@@ -72,6 +79,7 @@ static char __user *ksud_user_path(void)
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
}
#ifndef CONFIG_KSU_SUSFS
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *__unused_flags)
{
@@ -192,6 +200,142 @@ int ksu_handle_execve_sucompat(const char __user **filename_user,
return 0;
}
#else
static const char sh_path[] = SH_PATH;
static const char su_path[] = SU_PATH;
static const char ksud_path[] = KSUD_PATH;
extern bool ksu_kernel_umount_enabled;
// 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;
if (unlikely(!filename_ptr))
return 0;
filename = *filename_ptr;
if (IS_ERR(filename)) {
return 0;
}
if (likely(memcmp(filename->name, su_path, sizeof(su_path))))
return 0;
pr_info("do_execveat_common su found\n");
memcpy((void *)filename->name, ksud_path, sizeof(ksud_path));
escape_with_root_profile();
return 0;
}
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
void *envp, int *flags)
{
if (ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags)) {
return 0;
}
return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp,
flags);
}
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *__unused_flags)
{
char path[sizeof(su_path) + 1] = {0};
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (unlikely(!memcmp(path, su_path, sizeof(su_path)))) {
pr_info("faccessat su->sh!\n");
*filename_user = sh_user_path();
}
return 0;
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
int ksu_handle_stat(int *dfd, struct filename **filename, int *flags) {
if (unlikely(IS_ERR(*filename) || (*filename)->name == NULL)) {
return 0;
}
if (likely(memcmp((*filename)->name, su_path, sizeof(su_path)))) {
return 0;
}
pr_info("ksu_handle_stat: su->sh!\n");
memcpy((void *)((*filename)->name), sh_path, sizeof(sh_path));
return 0;
}
#else
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
{
if (unlikely(!filename_user)) {
return 0;
}
char path[sizeof(su_path) + 1] = {0};
// 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
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
struct filename *filename = *((struct filename **)filename_user);
#endif
if (IS_ERR(filename)) {
return 0;
}
if (likely(memcmp(filename->name, su_path, sizeof(su_path))))
return 0;
pr_info("ksu_handle_stat: su->sh!\n");
memcpy((void *)filename->name, sh_path, sizeof(sh_path));
#else
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (unlikely(!memcmp(path, su_path, sizeof(su_path)))) {
pr_info("ksu_handle_stat: su->sh!\n");
*filename_user = sh_user_path();
}
#endif
return 0;
}
#endif // #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
int ksu_handle_devpts(struct inode *inode)
{
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_for_current(uid))
return 0;
if (ksu_file_sid) {
struct inode_security_struct *sec = selinux_inode(inode);
if (sec) {
sec->sid = ksu_file_sid;
}
}
return 0;
}
#endif // #ifndef CONFIG_KSU_SUSFS
// sucompat: permitted process can execute 'su' to gain root access.
void ksu_sucompat_init()

View File

@@ -10,7 +10,11 @@ void ksu_sucompat_exit(void);
// Handler functions exported for hook_manager
int ksu_handle_faccessat(int *dfd, const char __user **filename_user,
int *mode, int *__unused_flags);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS)
int ksu_handle_stat(int *dfd, struct filename **filename, int *flags);
#else
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
#endif // #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS)
int ksu_handle_execve_sucompat(const char __user **filename_user,
void *__never_use_argv, void *__never_use_envp,
int *__never_use_flags);

View File

@@ -24,7 +24,9 @@
#include "selinux/selinux.h"
#include "objsec.h"
#include "file_wrapper.h"
#ifndef CONFIG_KSU_SUSFS
#include "syscall_hook_manager.h"
#endif
#include "throne_comm.h"
#include "dynamic_manager.h"
@@ -32,6 +34,56 @@
#include "manual_su.h"
#endif
#ifdef CONFIG_KSU_SUSFS
#include <linux/namei.h>
#include <linux/susfs.h>
bool susfs_is_boot_completed_triggered = false;
extern bool susfs_is_umount_for_zygote_system_process_enabled;
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
extern bool susfs_is_auto_add_sus_bind_mount_enabled;
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
extern bool susfs_is_auto_add_sus_ksu_default_mount_enabled;
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
extern bool susfs_is_auto_add_try_umount_for_bind_mount_enabled;
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
static 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
bool ksu_uid_scanner_enabled = false;
// Permission check functions
@@ -121,6 +173,10 @@ static int do_report_event(void __user *arg)
if (!post_fs_data_lock) {
post_fs_data_lock = true;
pr_info("post-fs-data triggered\n");
#ifdef CONFIG_KSU_SUSFS
susfs_on_post_fs_data();
pr_info("susfs_on_post_fs_data triggered\n");
#endif
on_post_fs_data();
init_uid_scanner();
#if __SULOG_GATE
@@ -136,6 +192,9 @@ static int do_report_event(void __user *arg)
boot_complete_lock = true;
pr_info("boot_complete triggered\n");
on_boot_completed();
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
susfs_is_boot_completed_triggered = true;
#endif
}
break;
}
@@ -422,7 +481,9 @@ put_orig_file:
static int do_manage_mark(void __user *arg)
{
struct ksu_manage_mark_cmd cmd;
#ifndef CONFIG_KSU_SUSFS
int ret = 0;
#endif
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("manage_mark: copy_from_user failed\n");
@@ -431,6 +492,7 @@ static int do_manage_mark(void __user *arg)
switch (cmd.operation) {
case KSU_MARK_GET: {
#ifndef CONFIG_KSU_SUSFS
// Get task mark status
ret = ksu_get_task_mark(cmd.pid);
if (ret < 0) {
@@ -439,8 +501,12 @@ static int do_manage_mark(void __user *arg)
}
cmd.result = (u32)ret;
break;
#else
return -EINVAL;
#endif
}
case KSU_MARK_MARK: {
#ifndef CONFIG_KSU_SUSFS
if (cmd.pid == 0) {
ksu_mark_all_process();
} else {
@@ -451,9 +517,13 @@ static int do_manage_mark(void __user *arg)
return ret;
}
}
#else
pr_info("susfs: cmd: KSU_MARK_MARK => do nothing\n");
#endif
break;
}
case KSU_MARK_UNMARK: {
#ifndef CONFIG_KSU_SUSFS
if (cmd.pid == 0) {
ksu_unmark_all_process();
} else {
@@ -464,11 +534,18 @@ static int do_manage_mark(void __user *arg)
return ret;
}
}
#else
pr_info("susfs: cmd: KSU_MARK_UNMARK => do nothing\n");
#endif
break;
}
case KSU_MARK_REFRESH: {
#ifndef CONFIG_KSU_SUSFS
ksu_mark_running_process();
pr_info("manage_mark: refreshed running processes\n");
#else
pr_info("susfs: cmd: KSU_MARK_REFRESH: do nothing\n");
#endif
break;
}
default: {
@@ -511,6 +588,8 @@ static int do_get_hook_type(void __user *arg)
#if defined(KSU_MANUAL_HOOK)
type = "Manual";
#elif defined(CONFIG_KSU_SUSFS)
type = "Inline";
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
@@ -717,6 +796,7 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
{ .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine
};
#ifndef CONFIG_KSU_SUSFS
struct ksu_install_fd_tw {
struct callback_head cb;
int __user *outp;
@@ -792,6 +872,142 @@ static struct kprobe reboot_kp = {
.pre_handler = reboot_handler_pre,
};
#endif
#else
int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg)
{
if (magic1 != KSU_INSTALL_MAGIC1) {
return -EINVAL;
}
// If magic2 is susfs and current process is root
if (magic2 == SUSFS_MAGIC && current_uid().val == 0) {
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
if (cmd == CMD_SUSFS_ADD_SUS_PATH) {
susfs_add_sus_path(arg);
return 0;
}
if (cmd == CMD_SUSFS_ADD_SUS_PATH_LOOP) {
susfs_add_sus_path_loop(arg);
return 0;
}
if (cmd == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) {
susfs_set_i_state_on_external_dir(arg);
return 0;
}
if (cmd == CMD_SUSFS_SET_SDCARD_ROOT_PATH) {
susfs_set_i_state_on_external_dir(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_PATH
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
if (cmd == CMD_SUSFS_ADD_SUS_MOUNT) {
susfs_add_sus_mount(arg);
return 0;
}
if (cmd == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) {
susfs_set_hide_sus_mnts_for_all_procs(arg);
return 0;
}
if (cmd == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) {
susfs_set_umount_for_zygote_iso_service(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
if (cmd == CMD_SUSFS_ADD_SUS_KSTAT) {
susfs_add_sus_kstat(arg);
return 0;
}
if (cmd == CMD_SUSFS_UPDATE_SUS_KSTAT) {
susfs_update_sus_kstat(arg);
return 0;
}
if (cmd == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) {
susfs_add_sus_kstat(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
if (cmd == CMD_SUSFS_ADD_TRY_UMOUNT) {
susfs_add_try_umount(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
if (cmd == CMD_SUSFS_SET_UNAME) {
susfs_set_uname(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG
if (cmd == CMD_SUSFS_ENABLE_LOG) {
susfs_enable_log(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG
#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
if (cmd == CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG) {
susfs_set_cmdline_or_bootconfig(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT
if (cmd == CMD_SUSFS_ADD_OPEN_REDIRECT) {
susfs_add_open_redirect(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT
#ifdef CONFIG_KSU_SUSFS_SUS_SU
if (cmd == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) {
susfs_get_sus_su_working_mode(arg);
return 0;
}
if (cmd == CMD_SUSFS_IS_SUS_SU_READY) {
susfs_is_sus_su_ready(arg);
return 0;
}
if (cmd == CMD_SUSFS_SUS_SU) {
susfs_sus_su(arg);
return 0;
}
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_SU
#ifdef CONFIG_KSU_SUSFS_SUS_MAP
if (cmd == CMD_SUSFS_ADD_SUS_MAP) {
susfs_add_sus_map(arg);
return 0;
}
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MAP
if (cmd == CMD_SUSFS_ENABLE_AVC_LOG_SPOOFING) {
susfs_set_avc_log_spoofing(arg);
return 0;
}
if (cmd == CMD_SUSFS_SHOW_ENABLED_FEATURES) {
susfs_get_enabled_features(arg);
return 0;
}
if (cmd == CMD_SUSFS_SHOW_VARIANT) {
susfs_show_variant(arg);
return 0;
}
if (cmd == CMD_SUSFS_SHOW_VERSION) {
susfs_show_version(arg);
return 0;
}
return 0;
}
// Check if this is a request to install KSU fd
if (magic2 == KSU_INSTALL_MAGIC2) {
int fd = ksu_install_fd();
pr_info("[%d] install ksu fd: %d\n", current->pid, fd);
if (copy_to_user((int *)*arg, &fd, sizeof(fd))) {
pr_err("install ksu fd reply err\n");
return 0;
}
}
return 0;
}
#endif // #ifndef CONFIG_KSU_SUSFS
void ksu_supercalls_init(void)
{
@@ -801,6 +1017,7 @@ void ksu_supercalls_init(void)
for (i = 0; ksu_ioctl_handlers[i].handler; i++) {
pr_info(" %-18s = 0x%08x\n", ksu_ioctl_handlers[i].name, ksu_ioctl_handlers[i].cmd);
}
#ifndef CONFIG_KSU_SUSFS
#ifdef KSU_KPROBES_HOOK
int rc = register_kprobe(&reboot_kp);
if (rc) {
@@ -809,13 +1026,18 @@ void ksu_supercalls_init(void)
pr_info("reboot kprobe registered successfully\n");
}
#endif
#endif
}
void ksu_supercalls_exit(void)
{
#ifndef CONFIG_KSU_SUSFS
#ifdef KSU_KPROBES_HOOK
unregister_kprobe(&reboot_kp);
#endif
#else
pr_info("susfs: do nothing\n");
#endif
}
static inline void ksu_ioctl_audit(unsigned int cmd, const char *cmd_name, uid_t uid, int ret)

View File

@@ -259,28 +259,28 @@ int ksu_handle_init_mark_tracker(const char __user **filename_user)
return 0;
}
#ifdef CONFIG_KSU_MANUAL_SU
#include "manual_su.h"
static inline void ksu_handle_task_alloc(struct pt_regs *regs)
{
ksu_try_escalate_for_uid(current_uid().val);
}
#endif
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
// Generic sys_enter handler that dispatches to specific handlers
static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id)
{
if (unlikely(check_syscall_fastpath(id))) {
#ifndef CONFIG_KSU_SUSFS
#ifdef KSU_TP_HOOK
if (ksu_su_compat_enabled) {
// Handle newfstatat
if (id == __NR_newfstatat) {
int *dfd = (int *)&PT_REGS_PARM1(regs);
const char __user **filename_user =
(const char __user **)&PT_REGS_PARM2(regs);
int *flags = (int *)&PT_REGS_SYSCALL_PARM4(regs);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS)
// Kernel 6.1+ with SUSFS uses struct filename **
struct filename **filename_ptr = (struct filename **)&PT_REGS_PARM2(regs);
ksu_handle_stat(dfd, filename_ptr, flags);
#else
// Older kernel or no SUSFS: use const char __user **
const char __user **filename_user = (const char __user **)&PT_REGS_PARM2(regs);
ksu_handle_stat(dfd, filename_user, flags);
#endif
return;
}
@@ -316,11 +316,6 @@ static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id)
ksu_handle_setresuid(ruid, euid, suid);
return;
}
#ifdef CONFIG_KSU_MANUAL_SU
// Handle task_alloc via clone/fork
if (id == __NR_clone || id == __NR_clone3)
return ksu_handle_task_alloc(regs);
#endif
}
}