diff --git a/kernel/arch.h b/kernel/arch.h index 739421d0..1678fd1b 100644 --- a/kernel/arch.h +++ b/kernel/arch.h @@ -8,7 +8,8 @@ #define __PT_PARM1_REG regs[0] #define __PT_PARM2_REG regs[1] #define __PT_PARM3_REG regs[2] -#define __PT_PARM4_REG regs[3] +#define __PT_SYSCALL_PARM4_REG regs[3] +#define __PT_CCALL_PARM4_REG regs[3] #define __PT_PARM5_REG regs[4] #define __PT_PARM6_REG regs[5] #define __PT_RET_REG regs[30] @@ -29,8 +30,8 @@ #define __PT_PARM2_REG si #define __PT_PARM3_REG dx /* syscall uses r10 for PARM4 */ -#define __PT_PARM4_REG r10 -// #define __PT_PARM4_REG cx +#define __PT_SYSCALL_PARM4_REG r10 +#define __PT_CCALL_PARM4_REG cx #define __PT_PARM5_REG r8 #define __PT_PARM6_REG r9 #define __PT_RET_REG sp @@ -56,7 +57,8 @@ #define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG) #define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG) #define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG) -#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG) +#define PT_REGS_SYSCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_SYSCALL_PARM4_REG) +#define PT_REGS_CCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_CCALL_PARM4_REG) #define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG) #define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG) #define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG) diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 654e2782..83413b47 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -559,7 +559,14 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs) int option = (int)PT_REGS_PARM1(real_regs); unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs); unsigned long arg3 = (unsigned long)PT_REGS_PARM3(real_regs); - unsigned long arg4 = (unsigned long)PT_REGS_PARM4(real_regs); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) + // PRCTL_SYMBOL is the arch-specificed one, which receive raw pt_regs from syscall + unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs); +#else + // PRCTL_SYMBOL is the common one, called by C convention in do_syscall_64 + // https://elixir.bootlin.com/linux/v4.15.18/source/arch/x86/entry/common.c#L287 + unsigned long arg4 = (unsigned long)PT_REGS_CCALL_PARM4(real_regs); +#endif unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs); return ksu_handle_prctl(option, arg2, arg3, arg4, arg5); @@ -579,7 +586,7 @@ static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs) struct dentry *new_entry = rd->new_dentry; #else struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs); - struct dentry *new_entry = (struct dentry *)PT_REGS_PARM4(regs); + struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs); #endif return ksu_handle_rename(old_entry, new_entry); diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c index 63377fc1..923b7998 100644 --- a/kernel/kernel_compat.c +++ b/kernel/kernel_compat.c @@ -65,11 +65,11 @@ void ksu_android_ns_fs_check() if (current->nsproxy && current->fs && current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) { android_context_saved_enabled = true; - pr_info("android contex saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n", + pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n", current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns); ksu_save_ns_fs(&android_context_saved); } else { - pr_info("android contex saved disabled\n"); + pr_info("android context saved disabled\n"); } task_unlock(current); } diff --git a/kernel/ksud.c b/kernel/ksud.c index faa458fb..55cd1997 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -138,8 +138,9 @@ static int __maybe_unused count(struct user_arg_ptr argv, int max) return i; } +// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags) + struct user_arg_ptr *argv, void *__never_use_envp, int *__never_use_flags) { #ifndef CONFIG_KPROBES if (!ksu_execveat_hook) { @@ -163,13 +164,11 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, if (unlikely(!memcmp(filename->name, system_bin_init, sizeof(system_bin_init) - 1))) { -#ifdef __aarch64__ // /system/bin/init executed - struct user_arg_ptr *ptr = (struct user_arg_ptr*) argv; - int argc = count(*ptr, MAX_ARG_STRINGS); + int argc = count(*argv, MAX_ARG_STRINGS); pr_info("/system/bin/init argc: %d\n", argc); if (argc > 1 && !init_second_stage_executed) { - const char __user *p = get_user_arg_ptr(*ptr, 1); + const char __user *p = get_user_arg_ptr(*argv, 1); if (p && !IS_ERR(p)) { char first_arg[16]; ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); @@ -184,20 +183,6 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, pr_err("/system/bin/init parse args err!\n"); } } -#else - // The argument parse is incorrect becuase of the struct user_arg_ptr has 16bytes - // and it is passed by value(not pointer), in arm64, it is correct becuase the register - // is just arranged correct accidentally, but is not correct in x86_64 - // i have no device to test, so revert it for x86_64 - static int init_count = 0; - if (++init_count == 2) { - // 1: /system/bin/init selinux_setup - // 2: /system/bin/init second_stage - pr_info("/system/bin/init second_stage executed\n"); - apply_kernelsu_rules(); - ksu_android_ns_fs_check(); - } -#endif } if (unlikely(first_app_process && @@ -394,11 +379,19 @@ 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); - void *argv = (void *)&PT_REGS_PARM3(regs); - void *envp = (void *)&PT_REGS_PARM4(regs); - int *flags = (int *)&PT_REGS_PARM5(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, envp, flags); + return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL); } static int read_handler_pre(struct kprobe *p, struct pt_regs *regs) @@ -406,7 +399,7 @@ static int read_handler_pre(struct kprobe *p, struct pt_regs *regs) struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs); char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs); size_t *count_ptr = (size_t *)&PT_REGS_PARM3(regs); - loff_t **pos_ptr = (loff_t **)&PT_REGS_PARM4(regs); + loff_t **pos_ptr = (loff_t **)&PT_REGS_CCALL_PARM4(regs); return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr); } @@ -416,7 +409,7 @@ static int input_handle_event_handler_pre(struct kprobe *p, { unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs); unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs); - int *value = (int *)&PT_REGS_PARM4(regs); + int *value = (int *)&PT_REGS_CCALL_PARM4(regs); return ksu_handle_input_handle_event(type, code, value); } diff --git a/kernel/sucompat.c b/kernel/sucompat.c index 3683cd55..1d40ece6 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -85,8 +85,9 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) return 0; } +// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags) + void *__never_use_argv, void *__never_use_envp, int *__never_use_flags) { struct filename *filename; const char sh[] = KSUD_PATH; @@ -121,7 +122,8 @@ static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs) int *dfd = (int *)PT_REGS_PARM1(regs); const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs); int *mode = (int *)&PT_REGS_PARM3(regs); - int *flags = (int *)&PT_REGS_PARM4(regs); + // Both sys_ and do_ is C function + int *flags = (int *)&PT_REGS_CCALL_PARM4(regs); return ksu_handle_faccessat(dfd, filename_user, mode, flags); } @@ -135,7 +137,7 @@ static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs) int *flags = (int *)&PT_REGS_PARM3(regs); #else // int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,int flag) - int *flags = (int *)&PT_REGS_PARM4(regs); + int *flags = (int *)&PT_REGS_CCALL_PARM4(regs); #endif return ksu_handle_stat(dfd, filename_user, flags); @@ -147,12 +149,8 @@ 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); - void *argv = (void *)&PT_REGS_PARM3(regs); - void *envp = (void *)&PT_REGS_PARM4(regs); - int *flags = (int *)&PT_REGS_PARM5(regs); - return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, - flags); + return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL); } static struct kprobe faccessat_kp = {