Distinguish different PT_REGS_PARM4 under x86 (#711)

1. `PT_REGS_CCALL_PARM4` 表示存放C调用约定的第4个参数的寄存器
2. `PT_REGS_SYSCALL_PARM4` 表示存放linux syscall调用约定的第4个参数的寄存器
3. 将原有 `PT_REGS_PARM4` 改为上述之一
4. 将原有 `ksu_handle_execveat_ksud` 和 `ksu_handle_execveat_sucompat` 可能被
kprobe 传递错误实参、且不使用的形参标记为 never_used 并传递 `NULL`
5. 为 `ksu_handle_execveat_ksud` 提供正确的 argv 参数用以在 x86 下也能正确识别 `init
second_stage`

---------

Co-authored-by: weishu <twsxtd@gmail.com>
This commit is contained in:
4qwerty7
2023-07-06 09:01:35 +08:00
committed by GitHub
parent 2c0a9cd64c
commit f4d2b0feab
5 changed files with 41 additions and 41 deletions

View File

@@ -8,7 +8,8 @@
#define __PT_PARM1_REG regs[0] #define __PT_PARM1_REG regs[0]
#define __PT_PARM2_REG regs[1] #define __PT_PARM2_REG regs[1]
#define __PT_PARM3_REG regs[2] #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_PARM5_REG regs[4]
#define __PT_PARM6_REG regs[5] #define __PT_PARM6_REG regs[5]
#define __PT_RET_REG regs[30] #define __PT_RET_REG regs[30]
@@ -29,8 +30,8 @@
#define __PT_PARM2_REG si #define __PT_PARM2_REG si
#define __PT_PARM3_REG dx #define __PT_PARM3_REG dx
/* syscall uses r10 for PARM4 */ /* syscall uses r10 for PARM4 */
#define __PT_PARM4_REG r10 #define __PT_SYSCALL_PARM4_REG r10
// #define __PT_PARM4_REG cx #define __PT_CCALL_PARM4_REG cx
#define __PT_PARM5_REG r8 #define __PT_PARM5_REG r8
#define __PT_PARM6_REG r9 #define __PT_PARM6_REG r9
#define __PT_RET_REG sp #define __PT_RET_REG sp
@@ -56,7 +57,8 @@
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG) #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_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_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_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_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) #define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)

View File

@@ -559,7 +559,14 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
int option = (int)PT_REGS_PARM1(real_regs); int option = (int)PT_REGS_PARM1(real_regs);
unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs); unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs);
unsigned long arg3 = (unsigned long)PT_REGS_PARM3(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); unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs);
return ksu_handle_prctl(option, arg2, arg3, arg4, arg5); 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; struct dentry *new_entry = rd->new_dentry;
#else #else
struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs); 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 #endif
return ksu_handle_rename(old_entry, new_entry); return ksu_handle_rename(old_entry, new_entry);

View File

@@ -65,11 +65,11 @@ void ksu_android_ns_fs_check()
if (current->nsproxy && current->fs && if (current->nsproxy && current->fs &&
current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) { current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) {
android_context_saved_enabled = true; 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); current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns);
ksu_save_ns_fs(&android_context_saved); ksu_save_ns_fs(&android_context_saved);
} else { } else {
pr_info("android contex saved disabled\n"); pr_info("android context saved disabled\n");
} }
task_unlock(current); task_unlock(current);
} }

View File

@@ -138,8 +138,9 @@ static int __maybe_unused count(struct user_arg_ptr argv, int max)
return i; 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, 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 #ifndef CONFIG_KPROBES
if (!ksu_execveat_hook) { 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, if (unlikely(!memcmp(filename->name, system_bin_init,
sizeof(system_bin_init) - 1))) { sizeof(system_bin_init) - 1))) {
#ifdef __aarch64__
// /system/bin/init executed // /system/bin/init executed
struct user_arg_ptr *ptr = (struct user_arg_ptr*) argv; int argc = count(*argv, MAX_ARG_STRINGS);
int argc = count(*ptr, MAX_ARG_STRINGS);
pr_info("/system/bin/init argc: %d\n", argc); pr_info("/system/bin/init argc: %d\n", argc);
if (argc > 1 && !init_second_stage_executed) { 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)) { if (p && !IS_ERR(p)) {
char first_arg[16]; char first_arg[16];
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); 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"); 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 && 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); int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr = struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs); (struct filename **)&PT_REGS_PARM2(regs);
void *argv = (void *)&PT_REGS_PARM3(regs); struct user_arg_ptr argv;
void *envp = (void *)&PT_REGS_PARM4(regs); #ifdef CONFIG_COMPAT
int *flags = (int *)&PT_REGS_PARM5(regs); 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) 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); struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs);
char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs); char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs);
size_t *count_ptr = (size_t *)&PT_REGS_PARM3(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); 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 *type = (unsigned int *)&PT_REGS_PARM2(regs);
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(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); return ksu_handle_input_handle_event(type, code, value);
} }

View File

@@ -85,8 +85,9 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
return 0; 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, 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; struct filename *filename;
const char sh[] = KSUD_PATH; 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); int *dfd = (int *)PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs); const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
int *mode = (int *)&PT_REGS_PARM3(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); 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); int *flags = (int *)&PT_REGS_PARM3(regs);
#else #else
// int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,int flag) // 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 #endif
return ksu_handle_stat(dfd, filename_user, flags); 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); int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr = struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs); (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, return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
flags);
} }
static struct kprobe faccessat_kp = { static struct kprobe faccessat_kp = {