From 49b01aad74bcca6dba5a8a2e053bb54b648eb124 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Thu, 14 Aug 2025 22:17:02 +0800 Subject: [PATCH] kernel: Introducing Tracepoint Hook Type Support Tracepoint is a predefined hook point in the kernel, compared to Kprobe, it is more stable and has lower performance overhead, although compatibility is relatively poor, it is still worth trying By the way, we have also included the config definitions related to hook types in Kconfig, to enhance cleanliness Improve and merge types that do not require hooks Introducing the hook type prctl These patches is based on https://github.com/backslashxx/KernelSU/issues/5 Co-authored-by: Cloud_Yun <1770669041@qq.com> Co-authored-by: Prslc Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> --- kernel/Kconfig | 22 +++++++++++ kernel/Makefile | 11 ++++++ kernel/core_hook.c | 19 +++++++++ kernel/ksu.c | 16 +++++++- kernel/ksu.h | 1 + kernel/ksu_trace.c | 82 +++++++++++++++++++++++++++++++++++++++ kernel/ksu_trace.h | 41 ++++++++++++++++++++ kernel/ksu_trace_export.c | 9 +++++ kernel/ksud.c | 22 +++++------ kernel/sucompat.c | 16 ++++---- 10 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 kernel/ksu_trace.c create mode 100644 kernel/ksu_trace.h create mode 100644 kernel/ksu_trace_export.c diff --git a/kernel/Kconfig b/kernel/Kconfig index 20012855..ddffdeb7 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -26,4 +26,26 @@ config KPM but it may affect system stability. select KALLSYMS select KALLSYMS_ALL + +choice + prompt "KernelSU hook type" + depends on KSU + default KSU_KPROBES_HOOK + help + Hook type for KernelSU + +config KSU_KPROBES_HOOK + bool "Hook KernelSU with Kprobes" + depends on KPROBES + help + If enabled, Hook required KernelSU syscalls with Kernel-probe. + +config KSU_TRACEPOINT_HOOK + bool "Hook KernelSU with Tracepoint" + depends on TRACEPOINTS + help + If enabled, Hook required KernelSU syscalls with Tracepoint. + +endchoice + endmenu diff --git a/kernel/Makefile b/kernel/Makefile index 460f8bd8..b6d93a5c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,6 +9,10 @@ kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o +ifeq ($(strip $(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 @@ -16,6 +20,7 @@ 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/ @@ -89,6 +94,12 @@ endif $(info -- Supported Unofficial Manager: 5ec1cff (GKI) ShirkNeko udochina (GKI and KPM)) +ifeq ($(strip $(CONFIG_KSU_KPROBES_HOOK)),y) +$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK) +else ifeq ($(strip $(CONFIG_KSU_TRACEPOINT_HOOK)),y) +$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK) +endif + KERNEL_VERSION := $(VERSION).$(PATCHLEVEL) KERNEL_TYPE := Non-GKI # Check for GKI 2.0 (5.10+ or 6.x+) diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 27476dfb..1e7c2046 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -522,6 +522,25 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, return 0; } + // Checking hook usage + if (arg2 == CMD_HOOK_TYPE) { + const char *hook_type; + +#if defined(CONFIG_KSU_KPROBES_HOOK) + hook_type = "Kprobes"; +#elif defined(CONFIG_KSU_TRACEPOINT_HOOK) + hook_type = "Tracepoint"; +#else + hook_type = "Unknown"; +#endif + + size_t len = strlen(hook_type) + 1; + if (copy_to_user((void __user *)arg3, hook_type, len)) { + pr_err("hook_type: copy_to_user failed\n"); + return 0; + } + } + #ifdef CONFIG_KPM // ADD: 添加KPM模块控制 if(sukisu_is_kpm_control_code(arg2)) { diff --git a/kernel/ksu.c b/kernel/ksu.c index 21f88be5..ae44c8f0 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -36,6 +36,10 @@ extern void ksu_sucompat_init(); extern void ksu_sucompat_exit(); extern void ksu_ksud_init(); extern void ksu_ksud_exit(); +#ifdef CONFIG_KSU_TRACEPOINT_HOOK +extern void ksu_trace_register(); +extern void ksu_trace_unregister(); +#endif int __init kernelsu_init(void) { @@ -56,13 +60,17 @@ int __init kernelsu_init(void) ksu_allowlist_init(); ksu_throne_tracker_init(); -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK ksu_sucompat_init(); ksu_ksud_init(); #else pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html"); #endif +#ifdef CONFIG_KSU_TRACEPOINT_HOOK + ksu_trace_register(); +#endif + #ifdef MODULE #ifndef CONFIG_KSU_DEBUG kobject_del(&THIS_MODULE->mkobj.kobj); @@ -79,11 +87,15 @@ void kernelsu_exit(void) destroy_workqueue(ksu_workqueue); -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK ksu_ksud_exit(); ksu_sucompat_exit(); #endif +#ifdef CONFIG_KSU_TRACEPOINT_HOOK + ksu_trace_unregister(); +#endif + ksu_core_exit(); } diff --git a/kernel/ksu.h b/kernel/ksu.h index 156c740d..257ee096 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -27,6 +27,7 @@ #define CMD_GET_FULL_VERSION 0xC0FFEE1A #define CMD_ENABLE_KPM 100 +#define CMD_HOOK_TYPE 101 #define CMD_DYNAMIC_SIGN 103 #define CMD_GET_MANAGERS 104 diff --git a/kernel/ksu_trace.c b/kernel/ksu_trace.c new file mode 100644 index 00000000..870e826d --- /dev/null +++ b/kernel/ksu_trace.c @@ -0,0 +1,82 @@ +#include "ksu_trace.h" + + +// extern kernelsu functions +extern bool ksu_execveat_hook __read_mostly; +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_execveat_sucompat(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) +{ + if (unlikely(ksu_execveat_hook)) + ksu_handle_execveat(fd, filename_ptr, argv, envp, flags); + else + ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL); +} + +void ksu_trace_execveat_sucompat_hook_callback(void *data, int *fd, struct filename **filename_ptr, + void *argv, void *envp, int *flags) +{ + if (!ksu_execveat_hook) + ksu_handle_execveat_sucompat(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_execveat_sucompat_hook(ksu_trace_execveat_sucompat_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_execveat_sucompat_hook(ksu_trace_execveat_sucompat_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 new file mode 100644 index 00000000..75200f98 --- /dev/null +++ b/kernel/ksu_trace.h @@ -0,0 +1,41 @@ +#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_execveat_sucompat_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 new file mode 100644 index 00000000..7fb1b1bc --- /dev/null +++ b/kernel/ksu_trace_export.c @@ -0,0 +1,9 @@ +#define CREATE_TRACE_POINTS +#include "ksu_trace.h" + +EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_hook); +EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_sucompat_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 ff0e685b..674d4589 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -48,7 +48,7 @@ static void stop_vfs_read_hook(); static void stop_execve_hook(); static void stop_input_hook(); -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK static struct work_struct stop_vfs_read_work; static struct work_struct stop_execve_hook_work; static struct work_struct stop_input_hook_work; @@ -162,7 +162,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, struct user_arg_ptr *argv, struct user_arg_ptr *envp, int *flags) { -#ifndef CONFIG_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_execveat_hook) { return 0; } @@ -318,7 +318,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_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_vfs_read_hook) { return 0; } @@ -431,7 +431,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_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_input_hook) { return 0; } @@ -473,7 +473,7 @@ bool ksu_is_safe_mode() return false; } -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) { struct pt_regs *real_regs = PT_REAL_REGS(regs); @@ -549,7 +549,7 @@ static void do_stop_input_hook(struct work_struct *work) static void stop_vfs_read_hook() { -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK bool ret = schedule_work(&stop_vfs_read_work); pr_info("unregister vfs_read kprobe: %d!\n", ret); #else @@ -560,7 +560,7 @@ static void stop_vfs_read_hook() static void stop_execve_hook() { -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK bool ret = schedule_work(&stop_execve_hook_work); pr_info("unregister execve kprobe: %d!\n", ret); #else @@ -576,7 +576,7 @@ static void stop_input_hook() return; } input_hook_stopped = true; -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK bool ret = schedule_work(&stop_input_hook_work); pr_info("unregister input kprobe: %d!\n", ret); #else @@ -588,7 +588,7 @@ static void stop_input_hook() // ksud: module support void ksu_ksud_init() { -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK int ret; ret = register_kprobe(&execve_kp); @@ -608,12 +608,12 @@ void ksu_ksud_init() void ksu_ksud_exit() { -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK unregister_kprobe(&execve_kp); // this should be done before unregister vfs_read_kp // unregister_kprobe(&vfs_read_kp); unregister_kprobe(&input_event_kp); +#endif is_boot_phase = false; -#endif } \ No newline at end of file diff --git a/kernel/sucompat.c b/kernel/sucompat.c index 6410947b..b29d4972 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -22,7 +22,7 @@ extern void escape_to_root(); -#ifndef CONFIG_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK static bool ksu_sucompat_non_kp __read_mostly = true; #endif @@ -54,7 +54,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, { const char su[] = SU_PATH; -#ifndef CONFIG_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_sucompat_non_kp) { return 0; } @@ -81,7 +81,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_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_sucompat_non_kp) { return 0; } @@ -130,7 +130,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, const char sh[] = KSUD_PATH; const char su[] = SU_PATH; -#ifndef CONFIG_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_sucompat_non_kp) { return 0; } @@ -164,7 +164,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_KPROBES +#ifndef CONFIG_KSU_KPROBES_HOOK if (!ksu_sucompat_non_kp){ return 0; } @@ -189,7 +189,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, return 0; } -#ifdef CONFIG_KPROBES +#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); @@ -258,7 +258,7 @@ static struct kprobe *su_kps[3]; // sucompat: permited process can execute 'su' to gain root access. void ksu_sucompat_init() { -#ifdef CONFIG_KPROBES +#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); @@ -270,7 +270,7 @@ void ksu_sucompat_init() void ksu_sucompat_exit() { -#ifdef CONFIG_KPROBES +#ifdef CONFIG_KSU_KPROBES_HOOK for (int i = 0; i < ARRAY_SIZE(su_kps); i++) { destroy_kprobe(&su_kps[i]); }