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]); }