kernel: sys_execve bprm simplified

Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-09-23 23:50:48 +08:00
parent 22634a71d6
commit 427000a9ec

View File

@@ -126,6 +126,12 @@ static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const c
if (!filename) if (!filename)
return 0; return 0;
// not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy)
// return 0;
if (likely(strcmp(filename, "/system/bin/init") && strcmp(filename, "/init")
&& !strstarts(filename, "/system/bin/app_process") ))
return 0;
// debug! remove me! // debug! remove me!
pr_info("%s: filename: %s argv1: %s envp_len: %zu\n", __func__, filename, argv1, envp_len); pr_info("%s: filename: %s argv1: %s envp_len: %zu\n", __func__, filename, argv1, envp_len);
@@ -154,6 +160,9 @@ static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const c
} }
} }
if (!envp || !envp_len)
goto first_app_process;
// /init without argv1/useless-argv1 but usable envp // /init without argv1/useless-argv1 but usable envp
// untested! TODO: test and debug me! // untested! TODO: test and debug me!
if (!init_second_stage_executed && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { if (!init_second_stage_executed && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) {
@@ -450,55 +459,46 @@ bool ksu_is_safe_mode()
} }
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef CONFIG_KSU_KPROBES_HOOK
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs);
struct user_arg_ptr argv;
#ifdef CONFIG_COMPAT
argv.is_compat = PT_REGS_PARM3(regs);
if (unlikely(argv.is_compat)) {
argv.ptr.compat = PT_REGS_CCALL_PARM4(regs);
} else {
argv.ptr.native = PT_REGS_CCALL_PARM4(regs);
}
#else
argv.ptr.native = PT_REGS_PARM3(regs);
#endif
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}
extern int ksu_bprm_check(struct linux_binprm *bprm);
static int bprm_check_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct linux_binprm *bprm_local = (struct linux_binprm *)PT_REGS_PARM1(regs);
return ksu_bprm_check(bprm_local);
};
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{ {
struct pt_regs *real_regs = PT_REAL_REGS(regs); struct pt_regs *real_regs = PT_REAL_REGS(regs);
const char __user **filename_user = const char __user *filename_user = (const char __user *)PT_REGS_PARM1(real_regs);
(const char **)&PT_REGS_PARM1(real_regs); const char __user *const __user *__argv = (const char __user *const __user *)PT_REGS_PARM2(real_regs);
const char __user *arg1_user = NULL;
char path[32]; char path[32];
char argv1[32] = {0};
if (!filename_user) if (!filename_user)
return 0; return 0;
// remember up ahead is ** so deref it with * if (ksu_copy_from_user_retry(path, filename_user, sizeof(path)))
long len = ksu_strncpy_from_user_nofault(path, *filename_user, 32);
if (len <= 0)
return 0; return 0;
path[sizeof(path) - 1] = '\0'; path[sizeof(path) - 1] = '\0';
return ksu_handle_pre_ksud(path); if (__argv) {
// grab argv[1] pointer
// this looks like
/*
* 0x1000 ./program << this is __argv
* 0x1001 -o
* 0x1002 arg
*/
if (ksu_copy_from_user_retry(&arg1_user, __argv + 1, sizeof(arg1_user)))
goto submit; // copy argv[1] pointer fail, probably no argv1 !!
if (arg1_user)
ksu_copy_from_user_retry(argv1, arg1_user, sizeof(argv1));
}
submit:
argv1[sizeof(argv1) - 1] = '\0';
#ifdef CONFIG_KSU_DEBUG
pr_info("%s: filename: %s argv[1]:%s\n", __func__, path, argv1);
#endif
return ksu_handle_bprm_ksud(path, argv1, "no_envp", strlen("no_envp"));
} }
static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
@@ -520,12 +520,7 @@ static int input_handle_event_handler_pre(struct kprobe *p,
return ksu_handle_input_handle_event(type, code, value); return ksu_handle_input_handle_event(type, code, value);
} }
static struct kprobe bprm_check_kp = { static struct kprobe execve_kp = {
.symbol_name = "security_bprm_check",
.pre_handler = bprm_check_handler_pre,
};
static struct kprobe sys_execve_kp = {
.symbol_name = SYS_EXECVE_SYMBOL, .symbol_name = SYS_EXECVE_SYMBOL,
.pre_handler = sys_execve_handler_pre, .pre_handler = sys_execve_handler_pre,
}; };
@@ -540,42 +535,6 @@ static struct kprobe input_event_kp = {
.pre_handler = input_handle_event_handler_pre, .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) static void do_stop_vfs_read_hook(struct work_struct *work)
{ {
unregister_kprobe(&vfs_read_kp); unregister_kprobe(&vfs_read_kp);
@@ -583,7 +542,7 @@ static void do_stop_vfs_read_hook(struct work_struct *work)
static void do_stop_execve_hook(struct work_struct *work) static void do_stop_execve_hook(struct work_struct *work)
{ {
unregister_execve_kprobe(); unregister_kprobe(&execve_kp);
} }
static void do_stop_input_hook(struct work_struct *work) static void do_stop_input_hook(struct work_struct *work)
@@ -686,9 +645,8 @@ void ksu_ksud_init(void)
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef CONFIG_KSU_KPROBES_HOOK
int ret; int ret;
ret = register_execve_kprobe(); ret = register_kprobe(&execve_kp);
if (ret) pr_info("ksud: execve_kp: %d\n", ret);
pr_err("ksud: failed to register any execve kprobe\n");
ret = register_kprobe(&vfs_read_kp); ret = register_kprobe(&vfs_read_kp);
pr_info("ksud: vfs_read_kp: %d\n", ret); pr_info("ksud: vfs_read_kp: %d\n", ret);
@@ -705,7 +663,7 @@ void ksu_ksud_init(void)
void ksu_ksud_exit(void) void ksu_ksud_exit(void)
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef CONFIG_KSU_KPROBES_HOOK
unregister_execve_kprobe(); unregister_kprobe(&execve_kp);
// this should be done before unregister vfs_read_kp // this should be done before unregister vfs_read_kp
// unregister_kprobe(&vfs_read_kp); // unregister_kprobe(&vfs_read_kp);
unregister_kprobe(&input_event_kp); unregister_kprobe(&input_event_kp);