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:
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user