diff --git a/kernel/ksud.c b/kernel/ksud.c index d4dcaeac..203ed787 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -50,7 +50,7 @@ static void stop_input_hook(); #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; @@ -450,6 +450,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); @@ -474,6 +495,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, @@ -484,14 +510,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) @@ -514,7 +576,7 @@ static void stop_vfs_read_hook() static void stop_execve_hook() { #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"); @@ -544,8 +606,9 @@ void ksu_ksud_init() #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); @@ -554,7 +617,7 @@ void ksu_ksud_init() 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 } @@ -562,7 +625,7 @@ void ksu_ksud_init() void ksu_ksud_exit() { #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);