diff --git a/.github/workflows/ddk-lkm.yml b/.github/workflows/ddk-lkm.yml index 689fe9d1..dedfc8c2 100644 --- a/.github/workflows/ddk-lkm.yml +++ b/.github/workflows/ddk-lkm.yml @@ -31,7 +31,7 @@ jobs: cd kernel echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ===" - CONFIG_KSU=m CONFIG_KSU_KPROBES_HOOK=y CONFIG_KSU_MANUAL_SU=y make + CONFIG_KSU=m CONFIG_KSU_TRACEPOINT_HOOK=y CONFIG_KSU_MANUAL_SU=y make echo "=== Build completed ===" # Create output directory in GitHub workspace diff --git a/kernel/Kconfig b/kernel/Kconfig index d197f65c..74ac8a12 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -36,17 +36,11 @@ config KPM choice prompt "KernelSU hook type" depends on KSU - default KSU_KPROBES_HOOK - -config KSU_KPROBES_HOOK - bool "Hook KernelSU with Kprobes" - depends on KPROBES - help - If enabled, Hook required KernelSU syscalls with Kernel-probe. + default KSU_TRACEPOINT_HOOK config KSU_TRACEPOINT_HOOK bool "Hook KernelSU with Tracepoint" - depends on TRACEPOINTS + depends on HAVE_SYSCALL_TRACEPOINTS help If enabled, Hook required KernelSU syscalls with Tracepoint. diff --git a/kernel/Makefile b/kernel/Makefile index 9bfe133e..2c0f27b7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -19,10 +19,6 @@ ccflags-y += -DCONFIG_KSU_MANUAL_SU kernelsu-objs += manual_su.o endif -ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) -kernelsu-objs += ksu_trace.o -endif - kernelsu-objs += selinux/selinux.o kernelsu-objs += selinux/sepolicy.o kernelsu-objs += selinux/rules.o @@ -30,7 +26,6 @@ ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h obj-$(CONFIG_KSU) += kernelsu.o -obj-$(CONFIG_KSU_TRACEPOINT_HOOK) += ksu_trace_export.o obj-$(CONFIG_KPM) += kpm/ @@ -124,15 +119,12 @@ ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\" $(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE)) endif -ifeq ($(CONFIG_KSU_KPROBES_HOOK), y) -$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK) -ccflags-y += -DCONFIG_KSU_KPROBES_HOOK -else ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) -$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK) -ccflags-y += -DCONFIG_KSU_TRACEPOINT_HOOK +ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) +$(info -- SukiSU: KSU_TRACEPOINT_HOOK) +ccflags-y += -DKSU_HAVE_SYSCALL_TRACEPOINTS_HOOK else ifeq ($(CONFIG_KSU_MANUAL_HOOK), y) -$(info -- SukiSU: CONFIG_KSU_MANUAL_HOOK) -ccflags-y += -DCONFIG_KSU_MANUAL_HOOK +$(info -- SukiSU: KSU_MANUAL_HOOK) +ccflags-y += -DKSU_MANUAL_HOOK endif KERNEL_VERSION := $(VERSION).$(PATCHLEVEL) diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 6db149eb..a8687bcf 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -92,10 +92,7 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE); #define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist" -static struct work_struct ksu_save_work; -static struct work_struct ksu_load_work; - -static bool persistent_allow_list(void); +void save_allow_list(void); void ksu_show_allow_list(void) { @@ -255,7 +252,7 @@ out: } if (persist) - persistent_allow_list(); + save_allow_list(); return result; } @@ -351,7 +348,8 @@ bool ksu_get_allow_list(int *array, int *length, bool allow) return true; } -static void do_save_allow_list(struct work_struct *work) +// make sure allow list works cross boot +void save_allow_list(void) { u32 magic = FILE_MAGIC; u32 version = FILE_FORMAT_VERSION; @@ -393,7 +391,7 @@ exit: filp_close(fp, 0); } -static void do_load_allow_list(struct work_struct *work) +void ksu_load_allow_list() { loff_t off = 0; ssize_t ret = 0; @@ -478,21 +476,10 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data mutex_unlock(&allowlist_mutex); if (modified) { - persistent_allow_list(); + save_allow_list(); } } -// make sure allow list works cross boot -static bool persistent_allow_list(void) -{ - return ksu_queue_work(&ksu_save_work); -} - -bool ksu_load_allow_list(void) -{ - return ksu_queue_work(&ksu_load_work); -} - void ksu_allowlist_init(void) { int i; @@ -505,9 +492,6 @@ void ksu_allowlist_init(void) INIT_LIST_HEAD(&allow_list); - INIT_WORK(&ksu_save_work, do_save_allow_list); - INIT_WORK(&ksu_load_work, do_load_allow_list); - init_default_profiles(); } @@ -516,7 +500,7 @@ void ksu_allowlist_exit(void) struct perm_data *np = NULL; struct perm_data *n = NULL; - do_save_allow_list(NULL); + save_allow_list(); // free allowlist mutex_lock(&allowlist_mutex); diff --git a/kernel/allowlist.h b/kernel/allowlist.h index 69297f84..24ef1518 100644 --- a/kernel/allowlist.h +++ b/kernel/allowlist.h @@ -8,7 +8,7 @@ void ksu_allowlist_init(void); void ksu_allowlist_exit(void); -bool ksu_load_allow_list(void); +void ksu_load_allow_list(void); void ksu_show_allow_list(void); diff --git a/kernel/core_hook.c b/kernel/core_hook.c index c11bdc8b..98c3bacb 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -1,3 +1,5 @@ +#include "linux/compiler.h" +#include "linux/sched/signal.h" #include #include #include @@ -47,6 +49,7 @@ #endif bool ksu_module_mounted = false; +extern bool ksu_su_compat_enabled; #ifdef CONFIG_COMPAT bool ksu_is_compat __read_mostly = false; @@ -175,6 +178,8 @@ static void disable_seccomp() void escape_to_root(void) { struct cred *cred; + struct task_struct *p = current; + struct task_struct *t; cred = prepare_creds(); if (!cred) { @@ -233,6 +238,10 @@ void escape_to_root(void) #if __SULOG_GATE ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root"); #endif + + for_each_thread(p, t){ + set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + } } #ifdef CONFIG_KSU_MANUAL_SU @@ -266,6 +275,8 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) { struct cred *newcreds; struct task_struct *target_task; + struct task_struct *p = current; + struct task_struct *t; pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid); @@ -347,6 +358,9 @@ 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 + for_each_thread(p, t){ + set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + } pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid); } #endif @@ -500,6 +514,12 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) return 0; } + if (new_uid.val == 2000) { + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } + } + 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; @@ -516,6 +536,9 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) ksu_install_fd(); spin_lock_irq(¤t->sighand->siglock); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } spin_unlock_irq(¤t->sighand->siglock); return 0; } @@ -527,6 +550,14 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); spin_unlock_irq(¤t->sighand->siglock); } + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } + } else { + // Disable syscall tracepoint sucompat for non-allowed processes + if (ksu_su_compat_enabled) { + clear_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } } // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it! @@ -549,7 +580,7 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) // 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 = is_zygote(old); if (!is_zygote_child) { pr_info("handle umount ignore non zygote child: %d\n", current->pid); return 0; diff --git a/kernel/include/ksu_hook.h b/kernel/include/ksu_hook.h deleted file mode 100644 index fb0eebc8..00000000 --- a/kernel/include/ksu_hook.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __KSU_H_KSHOOK -#define __KSU_H_KSHOOK - -#include -#include - -// For sucompat - -int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, - int *flags); - -int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); - -// For ksud - -int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, - size_t *count_ptr, loff_t **pos); - -// For ksud and sucompat - -int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags); - -// For volume button -int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, - int *value); - -#endif diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index 3d0b685c..bafc8611 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -6,12 +6,10 @@ #include "ss/policydb.h" #include "linux/key.h" -#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) -// arch/arm64/include/asm/barrier.h, adding dsb probably unneeded -#define DONT_GET_SMART() do { barrier(); isb(); } while (0) +#if defined(CONFIG_KPROBES) && !defined(KSU_MANUAL_HOOK) +#define KSU_KPROBES_HOOK 1 #else -// well, compiler atleast, and not our targets -#define DONT_GET_SMART() barrier() +#define KSU_KPROBES_HOOK 0 #endif /* diff --git a/kernel/ksu.c b/kernel/ksu.c index 987bf401..c9a55b0f 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -29,11 +29,6 @@ extern void ksu_sucompat_exit(); extern void ksu_ksud_init(); extern void ksu_ksud_exit(); extern void ksu_supercalls_init(); -#ifdef CONFIG_KSU_TRACEPOINT_HOOK -extern void ksu_trace_register(); -extern void ksu_trace_unregister(); -#endif - int __init kernelsu_init(void) { #ifdef CONFIG_KSU_DEBUG @@ -60,16 +55,12 @@ int __init kernelsu_init(void) ksu_sucompat_init(); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK ksu_ksud_init(); #else pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html"); #endif -#ifdef CONFIG_KSU_TRACEPOINT_HOOK - ksu_trace_register(); -#endif - #ifdef MODULE #ifndef CONFIG_KSU_DEBUG kobject_del(&THIS_MODULE->mkobj.kobj); @@ -90,14 +81,10 @@ void kernelsu_exit(void) ksu_sucompat_exit(); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK ksu_ksud_exit(); #endif -#ifdef CONFIG_KSU_TRACEPOINT_HOOK - ksu_trace_unregister(); -#endif - ksu_core_exit(); ksu_feature_exit(); } diff --git a/kernel/ksu_trace.c b/kernel/ksu_trace.c deleted file mode 100644 index e49c0a00..00000000 --- a/kernel/ksu_trace.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "ksu_trace.h" - - -// extern kernelsu functions -extern bool ksu_vfs_read_hook __read_mostly; -extern bool ksu_input_hook __read_mostly; -extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags); -extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, int *flags); -extern int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, size_t *count_ptr); -extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); -extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); -// end kernelsu functions - - -// tracepoint callback functions -void ksu_trace_execveat_hook_callback(void *data, int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags) -{ - ksu_handle_execveat(fd, filename_ptr, argv, envp, flags); -} - -void ksu_trace_faccessat_hook_callback(void *data, int *dfd, const char __user **filename_user, - int *mode, int *flags) -{ - ksu_handle_faccessat(dfd, filename_user, mode, flags); -} - -void ksu_trace_sys_read_hook_callback(void *data, unsigned int fd, char __user **buf_ptr, - size_t *count_ptr) -{ - if (unlikely(ksu_vfs_read_hook)) - ksu_handle_sys_read(fd, buf_ptr, count_ptr); -} - -void ksu_trace_stat_hook_callback(void *data, int *dfd, const char __user **filename_user, - int *flags) -{ - ksu_handle_stat(dfd, filename_user, flags); -} - -void ksu_trace_input_hook_callback(void *data, unsigned int *type, unsigned int *code, - int *value) -{ - if (unlikely(ksu_input_hook)) - ksu_handle_input_handle_event(type, code, value); -} - -// end tracepoint callback functions - - -// register tracepoint callback functions -void ksu_trace_register(void) -{ - register_trace_ksu_trace_execveat_hook(ksu_trace_execveat_hook_callback, NULL); - register_trace_ksu_trace_faccessat_hook(ksu_trace_faccessat_hook_callback, NULL); - register_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback, NULL); - register_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL); - register_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback, NULL); -} - -// unregister tracepoint callback functions -void ksu_trace_unregister(void) -{ - unregister_trace_ksu_trace_execveat_hook(ksu_trace_execveat_hook_callback, NULL); - unregister_trace_ksu_trace_faccessat_hook(ksu_trace_faccessat_hook_callback, NULL); - unregister_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback, NULL); - unregister_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL); - unregister_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback, NULL); -} diff --git a/kernel/ksu_trace.h b/kernel/ksu_trace.h deleted file mode 100644 index 77425638..00000000 --- a/kernel/ksu_trace.h +++ /dev/null @@ -1,37 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM ksu_trace - -#if !defined(_KSU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _KSU_TRACE_H - -#include -#include - -DECLARE_TRACE(ksu_trace_execveat_hook, - TP_PROTO(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags), - TP_ARGS(fd, filename_ptr, argv, envp, flags)); - -DECLARE_TRACE(ksu_trace_faccessat_hook, - TP_PROTO(int *dfd, const char __user **filename_user, int *mode, int *flags), - TP_ARGS(dfd, filename_user, mode, flags)); - -DECLARE_TRACE(ksu_trace_sys_read_hook, - TP_PROTO(unsigned int fd, char __user **buf_ptr, size_t *count_ptr), - TP_ARGS(fd, buf_ptr, count_ptr)); - -DECLARE_TRACE(ksu_trace_stat_hook, - TP_PROTO(int *dfd, const char __user **filename_user, int *flags), - TP_ARGS(dfd, filename_user, flags)); - -DECLARE_TRACE(ksu_trace_input_hook, - TP_PROTO(unsigned int *type, unsigned int *code, int *value), - TP_ARGS(type, code, value)); - -#endif /* _KSU_TRACE_H */ - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE ksu_trace - -#include diff --git a/kernel/ksu_trace_export.c b/kernel/ksu_trace_export.c deleted file mode 100644 index b303cbbd..00000000 --- a/kernel/ksu_trace_export.c +++ /dev/null @@ -1,8 +0,0 @@ -#define CREATE_TRACE_POINTS -#include "ksu_trace.h" - -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_faccessat_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_sys_read_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_stat_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_input_hook); diff --git a/kernel/ksud.c b/kernel/ksud.c index fe153900..ac6897cd 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -49,7 +49,7 @@ static void stop_vfs_read_hook(); static void stop_execve_hook(); static void stop_input_hook(); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK static struct work_struct stop_vfs_read_work; static struct work_struct stop_execve_hook_work; static struct work_struct stop_input_hook_work; @@ -74,6 +74,9 @@ void on_post_fs_data(void) done = true; pr_info("on_post_fs_data!\n"); ksu_load_allow_list(); + extern void ksu_mark_running_process(void); + pr_info("mark tif for running process\n"); + ksu_mark_running_process(); ksu_observer_init(); // sanity check, this may influence the performance stop_input_hook(); @@ -268,7 +271,7 @@ static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to) int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, size_t *count_ptr, loff_t **pos) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_KPROBES_HOOK if (!ksu_vfs_read_hook) { return 0; } @@ -381,7 +384,7 @@ static bool is_volumedown_enough(unsigned int count) int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_KPROBES_HOOK if (!ksu_input_hook) { return 0; } @@ -423,7 +426,7 @@ bool ksu_is_safe_mode() return false; } -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) { /* @@ -596,7 +599,7 @@ static void do_stop_input_hook(struct work_struct *work) static void stop_vfs_read_hook() { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK bool ret = schedule_work(&stop_vfs_read_work); pr_info("unregister vfs_read kprobe: %d!\n", ret); #else @@ -607,7 +610,7 @@ static void stop_vfs_read_hook() static void stop_execve_hook() { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK bool ret = schedule_work(&stop_execve_hook_work); pr_info("unregister execve kprobe: %d!\n", ret); #else @@ -623,7 +626,7 @@ static void stop_input_hook() return; } input_hook_stopped = true; -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK bool ret = schedule_work(&stop_input_hook_work); pr_info("unregister input kprobe: %d!\n", ret); #else @@ -635,7 +638,7 @@ static void stop_input_hook() // ksud: module support void ksu_ksud_init() { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK int ret; ret = register_kprobe(&execve_kp); @@ -655,7 +658,7 @@ void ksu_ksud_init() void ksu_ksud_exit() { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK unregister_kprobe(&execve_kp); // this should be done before unregister vfs_read_kp // unregister_kprobe(&vfs_read_kp); diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index c95952a0..7b8e4cd9 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -1,4 +1,6 @@ #include "selinux.h" +#include "linux/cred.h" +#include "linux/sched.h" #include "objsec.h" #include "linux/version.h" #include "../klog.h" // IWYU pragma: keep @@ -84,7 +86,7 @@ static inline u32 current_sid(void) } #endif -bool is_ksu_domain() +bool is_task_ksu_domain(const struct cred* cred) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) struct lsm_context ctx; @@ -93,10 +95,17 @@ bool is_ksu_domain() u32 seclen; #endif bool result; + if (!cred) { + return false; + } + const struct task_security_struct *tsec = selinux_cred(cred); + if (!tsec) { + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - int err = security_secid_to_secctx(current_sid(), &ctx); + int err = security_secid_to_secctx(tsec->sid, &ctx); #else - int err = security_secid_to_secctx(current_sid(), &domain, &seclen); + int err = security_secid_to_secctx(tsec->sid, &domain, &seclen); #endif if (err) { @@ -113,9 +122,18 @@ bool is_ksu_domain() return result; } -bool is_zygote(void *sec) +bool is_ksu_domain() { - struct task_security_struct *tsec = (struct task_security_struct *)sec; + current_sid(); + return is_task_ksu_domain(current_cred()); +} + +bool is_zygote(const struct cred* cred) +{ + if (!cred) { + return false; + } + const struct task_security_struct * tsec = selinux_cred(cred); if (!tsec) { return false; } diff --git a/kernel/selinux/selinux.h b/kernel/selinux/selinux.h index 88f1e7d3..75824fc7 100644 --- a/kernel/selinux/selinux.h +++ b/kernel/selinux/selinux.h @@ -3,6 +3,7 @@ #include "linux/types.h" #include "linux/version.h" +#include "linux/sched.h" void setup_selinux(const char *); @@ -10,9 +11,11 @@ void setenforce(bool); bool getenforce(); +bool is_task_ksu_domain(const struct cred* cred); + bool is_ksu_domain(); -bool is_zygote(void *cred); +bool is_zygote(const struct cred* cred); void apply_kernelsu_rules(); diff --git a/kernel/sucompat.c b/kernel/sucompat.c index b710df6c..4175a69f 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -1,3 +1,6 @@ +#include "linux/compiler.h" +#include "linux/sched.h" +#include "selinux/selinux.h" #include #include #include @@ -5,10 +8,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include "objsec.h" #include "allowlist.h" @@ -62,7 +68,7 @@ static const struct ksu_feature_handler su_compat_handler = { .set_handler = su_compat_feature_set, }; -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK static bool ksu_sucompat_hook_state __read_mostly = true; #endif @@ -94,7 +100,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, { const char su[] = SU_PATH; -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -124,7 +130,7 @@ 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 +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -182,7 +188,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, const char sh[] = KSUD_PATH; const char su[] = SU_PATH; -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -228,7 +234,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, const char su[] = SU_PATH; char path[sizeof(su) + 1]; -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state){ return 0; } @@ -273,7 +279,7 @@ int ksu_handle_devpts(struct inode *inode) int __ksu_handle_devpts(struct inode *inode) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) return 0; #endif @@ -299,40 +305,45 @@ int __ksu_handle_devpts(struct inode *inode) return 0; } -#ifdef CONFIG_KSU_KPROBES_HOOK -static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *mode = (int *)&PT_REGS_PARM3(real_regs); +#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK - return ksu_handle_faccessat(dfd, filename_user, mode, NULL); +// Tracepoint probe for sys_enter +static void sucompat_sys_enter_handler(void *data, struct pt_regs *regs, + long id) +{ + // Handle newfstatat + if (unlikely(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); + ksu_handle_stat(dfd, filename_user, flags); + return; + } + + // Handle faccessat + if (unlikely(id == __NR_faccessat)) { + int *dfd = (int *)&PT_REGS_PARM1(regs); + const char __user **filename_user = + (const char __user **)&PT_REGS_PARM2(regs); + int *mode = (int *)&PT_REGS_PARM3(regs); + ksu_handle_faccessat(dfd, filename_user, mode, NULL); + return; + } + + // Handle execve + if (unlikely(id == __NR_execve)) { + const char __user **filename_user = + (const char __user **)&PT_REGS_PARM1(regs); + ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, NULL); + return; + } } -static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs); +#endif // KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK - return ksu_handle_stat(dfd, filename_user, flags); -} +#ifdef KSU_KPROBES_HOOK -static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM1(real_regs); - - return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, - NULL); -} - -static struct kprobe *su_kps[4]; static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) { struct inode *inode; @@ -347,7 +358,7 @@ static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) } static struct kprobe *init_kprobe(const char *name, - kprobe_pre_handler_t handler) + kprobe_pre_handler_t handler) { struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL); if (!kp) @@ -376,32 +387,81 @@ static void destroy_kprobe(struct kprobe **kp_ptr) *kp_ptr = NULL; } +static struct kprobe *pts_kp = NULL; #endif -// sucompat: permited process can execute 'su' to gain root access. +void ksu_mark_running_process() +{ + struct task_struct *p, *t; + read_lock(&tasklist_lock); + for_each_process_thread (p, t) { + if (!t->mm) { // only user processes + continue; + } + int uid = task_uid(t).val; + bool ksu_root_process = + uid == 0 && is_task_ksu_domain(get_task_cred(t)); + if (ksu_root_process || ksu_is_allow_uid(uid)) { + set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + pr_info("sucompat: mark process: pid:%d, uid: %d, comm:%s\n", + t->pid, uid, t->comm); + } + } + read_unlock(&tasklist_lock); +} + +static void unmark_all_process() +{ + struct task_struct *p, *t; + read_lock(&tasklist_lock); + for_each_process_thread (p, t) { + clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + } + read_unlock(&tasklist_lock); + pr_info("sucompat: unmark all user process done!\n"); +} + void ksu_sucompat_enable() { -#ifdef CONFIG_KSU_KPROBES_HOOK - su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); - su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); - su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre); - su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); + int ret; + pr_info("sucompat: ksu_sucompat_enable called\n"); +#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK + // Register sys_enter tracepoint for syscall interception + ret = register_trace_sys_enter(sucompat_sys_enter_handler, NULL); + unmark_all_process(); + ksu_mark_running_process(); + if (ret) { + pr_err("sucompat: failed to register sys_enter tracepoint: %d\n", ret); + } else { + pr_info("sucompat: sys_enter tracepoint registered\n"); + } #else ksu_sucompat_hook_state = true; pr_info("ksu_sucompat_init: hooks enabled: execve/execveat_su, faccessat, stat\n"); #endif + +#ifdef KSU_KPROBES_HOOK + // Register kprobe for pts_unix98_lookup + pts_kp = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); +#endif } void ksu_sucompat_disable() { -#ifdef CONFIG_KSU_KPROBES_HOOK - int i; - for (i = 0; i < ARRAY_SIZE(su_kps); i++) { - destroy_kprobe(&su_kps[i]); - } + pr_info("sucompat: ksu_sucompat_disable called\n"); +#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK + // Unregister sys_enter tracepoint + unregister_trace_sys_enter(sucompat_sys_enter_handler, NULL); + tracepoint_synchronize_unregister(); + pr_info("sucompat: sys_enter tracepoint unregistered\n"); #else ksu_sucompat_hook_state = false; - pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat\n"); + pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat\n"); +#endif + +#ifdef KSU_KPROBES_HOOK + // Unregister pts_unix98_lookup kprobe + destroy_kprobe(&pts_kp); #endif } @@ -422,5 +482,4 @@ void ksu_sucompat_exit() ksu_sucompat_disable(); } ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT); -} - +} \ No newline at end of file diff --git a/kernel/supercalls.c b/kernel/supercalls.c index 9adab23e..61279dec 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -385,11 +385,11 @@ static int do_get_full_version(void __user *arg) static int do_get_hook_type(void __user *arg) { struct ksu_hook_type_cmd cmd = {0}; - const char *type = "Kprobes"; + const char *type = "Unknown"; -#if defined(CONFIG_KSU_TRACEPOINT_HOOK) +#if defined(KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK) type = "Tracepoint"; -#elif defined(CONFIG_KSU_MANUAL_HOOK) +#elif defined(KSU_MANUAL_HOOK) type = "Manual"; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)