From 22634a71d637359d29026806c1b71d71defedb30 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:20:48 +0800 Subject: [PATCH] kernel ksud: Attempt registration with `bprm_check_kp` first. If it fails, fall back to `sys_execve_kp`. Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com> Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> --- kernel/ksud.c | 79 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/kernel/ksud.c b/kernel/ksud.c index c045605e..8e4c3bf8 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -56,7 +56,7 @@ static void stop_input_hook(void); #ifdef CONFIG_KSU_KPROBES_HOOK static struct work_struct stop_vfs_read_work; -static struct work_struct stop_bprm_check_work; +static struct work_struct stop_execve_hook_work; static struct work_struct stop_input_hook_work; #else bool ksu_vfs_read_hook __read_mostly = true; @@ -480,6 +480,27 @@ static int bprm_check_handler_pre(struct kprobe *p, struct pt_regs *regs) return ksu_bprm_check(bprm_local); }; +static int sys_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); + + char path[32]; + + if (!filename_user) + return 0; + + // remember up ahead is ** so deref it with * + long len = ksu_strncpy_from_user_nofault(path, *filename_user, 32); + if (len <= 0) + return 0; + + path[sizeof(path) - 1] = '\0'; + + return ksu_handle_pre_ksud(path); +} + static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) { struct pt_regs *real_regs = PT_REAL_REGS(regs); @@ -504,6 +525,11 @@ static struct kprobe bprm_check_kp = { .pre_handler = bprm_check_handler_pre, }; +static struct kprobe sys_execve_kp = { + .symbol_name = SYS_EXECVE_SYMBOL, + .pre_handler = sys_execve_handler_pre, +}; + static struct kprobe vfs_read_kp = { .symbol_name = SYS_READ_SYMBOL, .pre_handler = sys_read_handler_pre, @@ -514,14 +540,50 @@ static struct kprobe input_event_kp = { .pre_handler = input_handle_event_handler_pre, }; +static struct kprobe *execve_kprobe = NULL; + +static int register_execve_kprobe(void) +{ + int ret; + + ret = register_kprobe(&bprm_check_kp); + if (ret == 0) { + execve_kprobe = &bprm_check_kp; + pr_info("ksud: registered bprm_check_kprobe\n"); + return 0; + } + + pr_warn("ksud: failed to register bprm_check_kprobe (%d), falling back to sys_execve_kprobe\n", ret); + + ret = register_kprobe(&sys_execve_kp); + if (ret == 0) { + execve_kprobe = &sys_execve_kp; + pr_info("ksud: registered sys_execve_kprobe\n"); + return 0; + } + + pr_err("ksud: failed to register sys_execve_kprobe (%d)\n", ret); + return ret; +} + +static void unregister_execve_kprobe(void) +{ + if (execve_kprobe) { + unregister_kprobe(execve_kprobe); + pr_info("ksud: unregistered %s\n", + execve_kprobe == &bprm_check_kp ? "bprm_check_kprobe" : "sys_execve_kprobe"); + execve_kprobe = NULL; + } +} + static void do_stop_vfs_read_hook(struct work_struct *work) { unregister_kprobe(&vfs_read_kp); } -static void do_stop_bprm_check_hook(struct work_struct *work) +static void do_stop_execve_hook(struct work_struct *work) { - unregister_kprobe(&bprm_check_kp); + unregister_execve_kprobe(); } static void do_stop_input_hook(struct work_struct *work) @@ -589,7 +651,7 @@ static void stop_vfs_read_hook(void) static void stop_execve_hook(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - bool ret = schedule_work(&stop_bprm_check_work); + bool ret = schedule_work(&stop_execve_hook_work); pr_info("unregister execve kprobe: %d!\n", ret); #else pr_info("stop execve_hook\n"); @@ -624,8 +686,9 @@ void ksu_ksud_init(void) #ifdef CONFIG_KSU_KPROBES_HOOK int ret; - ret = register_kprobe(&bprm_check_kp); - pr_info("ksud: bprm_check_kp: %d\n", ret); + ret = register_execve_kprobe(); + if (ret) + pr_err("ksud: failed to register any execve kprobe\n"); ret = register_kprobe(&vfs_read_kp); pr_info("ksud: vfs_read_kp: %d\n", ret); @@ -634,7 +697,7 @@ void ksu_ksud_init(void) pr_info("ksud: input_event_kp: %d\n", ret); INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook); - INIT_WORK(&stop_bprm_check_work, do_stop_bprm_check_hook); + INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook); INIT_WORK(&stop_input_hook_work, do_stop_input_hook); #endif } @@ -642,7 +705,7 @@ void ksu_ksud_init(void) void ksu_ksud_exit(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - unregister_kprobe(&bprm_check_kp); + unregister_execve_kprobe(); // this should be done before unregister vfs_read_kp // unregister_kprobe(&vfs_read_kp); unregister_kprobe(&input_event_kp);