Skip to content

Commit

Permalink
Hook syscalls and stable symbols
Browse files Browse the repository at this point in the history
1. Replace `do_execveat_common` with `sys_execve` and `sys_execveat`
2. Replace `input_handle_event` with `input_event` and `input_inject_event`
  • Loading branch information
anotherjin committed Apr 23, 2024
1 parent 825b146 commit 13568bb
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 5 deletions.
8 changes: 8 additions & 0 deletions kernel/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@
#define SYS_READ_SYMBOL "__arm64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
#define SYS_EXECVEAT_SYMBOL "__arm64_sys_execveat"
#define COMPAT_SYS_EXECVE_SYMBOL "__arm64_compat_sys_execve"
#define COMPAT_SYS_EXECVEAT_SYMBOL "__arm64_compat_sys_execveat"
#else
#define PRCTL_SYMBOL "sys_prctl"
#define SYS_READ_SYMBOL "sys_read"
#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "sys_faccessat"
#define SYS_EXECVE_SYMBOL "sys_execve"
#define SYS_EXECVEAT_SYMBOL "sys_execveat"
#define COMPAT_SYS_EXECVE_SYMBOL "compat_sys_execve"
#define COMPAT_SYS_EXECVEAT_SYMBOL "compat_sys_execveat"
#endif

#elif defined(__x86_64__)
Expand Down
142 changes: 137 additions & 5 deletions kernel/ksud.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "linux/err.h"
#include "linux/file.h"
#include "linux/fs.h"
#include "linux/namei.h"
#include "linux/version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#include "linux/input-event-codes.h"
Expand Down Expand Up @@ -472,6 +473,89 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}

static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
const char __user *filename_user =
(const char *)PT_REGS_PARM1(real_regs);
struct filename *filename_mid = getname(filename_user);
struct filename **filename_ptr = (struct filename **)&filename_mid;
const char __user *const __user *__argv =
(const char __user *const __user *)PT_REGS_PARM2(real_regs);
struct user_arg_ptr argv = { .ptr.native = __argv };

return ksu_handle_execveat_ksud(AT_FDCWD, filename_ptr, &argv, NULL,
NULL);
}

static int sys_execveat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
int *fd = (int *)&PT_REGS_PARM1(real_regs);
const char __user *filename_user =
(const char *)PT_REGS_PARM2(real_regs);
int flags = PT_REGS_PARM5(real_regs);
int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
struct filename *filename_mid =
getname_flags(filename_user, lookup_flags, NULL);
struct filename **filename_ptr = (struct filename **)&filename_mid;
const char __user *const __user *__argv =
(const char __user *const __user *)PT_REGS_PARM3(real_regs);
struct user_arg_ptr argv = { .ptr.native = __argv };

return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}

static int compat_sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
const char __user *filename_user =
(const char *)PT_REGS_PARM1(real_regs);
struct filename *filename_mid = getname(filename_user);
struct filename **filename_ptr = (struct filename **)&filename_mid;
const compat_uptr_t __user *__argv =
(const compat_uptr_t *)PT_REGS_PARM2(real_regs);
struct user_arg_ptr argv = { .ptr.compat = __argv, .is_compat = true };

return ksu_handle_execveat_ksud(AT_FDCWD, filename_ptr, &argv, NULL,
NULL);
}

static int compat_sys_execveat_handler_pre(struct kprobe *p,
struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
int *fd = (int *)&PT_REGS_PARM1(real_regs);
const char __user *filename_user =
(const char *)PT_REGS_PARM2(real_regs);
int flags = PT_REGS_PARM5(real_regs);
int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
struct filename *filename_mid =
getname_flags(filename_user, lookup_flags, NULL);
struct filename **filename_ptr = (struct filename **)&filename_mid;
const compat_uptr_t __user *__argv =
(const compat_uptr_t *)PT_REGS_PARM3(real_regs);
struct user_arg_ptr argv = { .ptr.compat = __argv, .is_compat = true };

return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}

// remove this later!
__maybe_unused static int vfs_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
Expand Down Expand Up @@ -506,6 +590,32 @@ static int input_handle_event_handler_pre(struct kprobe *p,
return ksu_handle_input_handle_event(type, code, value);
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe execve_syscall_kp = {
.symbol_name = SYS_EXECVE_SYMBOL,
.pre_handler = sys_execve_handler_pre,
};

static struct kprobe execveat_syscall_kp = {
.symbol_name = SYS_EXECVEAT_SYMBOL,
.pre_handler = sys_execveat_handler_pre,
};

static struct kprobe compat_execve_syscall_kp = {
.symbol_name = COMPAT_SYS_EXECVE_SYMBOL,
.pre_handler = compat_sys_execve_handler_pre,
};

static struct kprobe compat_execveat_syscall_kp = {
.symbol_name = COMPAT_SYS_EXECVEAT_SYMBOL,
.pre_handler = compat_sys_execveat_handler_pre,
};

static struct kprobe *execve_kps[] = {
&execve_syscall_kp, &compat_execve_syscall_kp,
&execveat_syscall_kp, &compat_execveat_syscall_kp
};
#else
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
.symbol_name = "do_execveat_common",
Expand All @@ -516,6 +626,7 @@ static struct kprobe execve_kp = {
#endif
.pre_handler = execve_handler_pre,
};
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe vfs_read_kp = {
Expand All @@ -529,24 +640,37 @@ static struct kprobe vfs_read_kp = {
};
#endif

static struct kprobe input_handle_event_kp = {
.symbol_name = "input_handle_event",
static struct kprobe input_event_kp = {
.symbol_name = "input_event",
.pre_handler = input_handle_event_handler_pre,
};

static struct kprobe input_inject_event_kp = {
.symbol_name = "input_inject_event",
.pre_handler = input_handle_event_handler_pre,
};

static struct kprobe *input_event_kps[] = {
&input_event_kp, &input_inject_event_kp
};

static void do_stop_vfs_read_hook(struct work_struct *work)
{
unregister_kprobe(&vfs_read_kp);
}

static void do_stop_execve_hook(struct work_struct *work)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
unregister_kprobes(execve_kps, 4);
#else
unregister_kprobe(&execve_kp);
#endif
}

static void do_stop_input_hook(struct work_struct *work)
{
unregister_kprobe(&input_handle_event_kp);
unregister_kprobes(input_event_kps, 2);
}
#endif

Expand Down Expand Up @@ -594,13 +718,17 @@ void ksu_ksud_init()
#ifdef CONFIG_KPROBES
int ret;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
ret = register_kprobes(execve_kps, 4);
#else
ret = register_kprobe(&execve_kp);
#endif
pr_info("ksud: execve_kp: %d\n", ret);

ret = register_kprobe(&vfs_read_kp);
pr_info("ksud: vfs_read_kp: %d\n", ret);

ret = register_kprobe(&input_handle_event_kp);
ret = register_kprobes(input_event_kps, 2);
pr_info("ksud: input_handle_event_kp: %d\n", ret);

INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
Expand All @@ -611,9 +739,13 @@ void ksu_ksud_init()

void ksu_ksud_exit() {
#ifdef CONFIG_KPROBES
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
unregister_kprobes(execve_kps, 4);
#else
unregister_kprobe(&execve_kp);
#endif
// this should be done before unregister vfs_read_kp
// unregister_kprobe(&vfs_read_kp);
unregister_kprobe(&input_handle_event_kp);
unregister_kprobe(&input_event_kp);
#endif
}
70 changes: 70 additions & 0 deletions kernel/sucompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/version.h"
#include "linux/namei.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include "linux/sched/task_stack.h"
#else
Expand Down Expand Up @@ -196,6 +197,39 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
}

static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
const char __user *filename_user =
(const char *)PT_REGS_PARM1(real_regs);
struct filename *filename_mid = getname(filename_user);
struct filename **filename_ptr = (struct filename **)&filename_mid;

return ksu_handle_execveat_sucompat(AT_FDCWD, filename_ptr, NULL, NULL, NULL);
}

static int sys_execveat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
int *fd = (int *)&PT_REGS_PARM1(real_regs);
const char __user *filename_user =
(const char *)PT_REGS_PARM2(real_regs);
int flags = PT_REGS_PARM5(real_regs);
int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
struct filename *filename_mid = getname_flags(filename_user, lookup_flags, NULL);
struct filename **filename_ptr = (struct filename **)&filename_mid;

return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe faccessat_kp = {
.symbol_name = SYS_FACCESSAT_SYMBOL,
Expand Down Expand Up @@ -228,6 +262,33 @@ static struct kprobe newfstatat_kp = {
};
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe execve_syscall_kp = {
.symbol_name = SYS_EXECVE_SYMBOL,
.pre_handler = sys_execve_handler_pre,
};

static struct kprobe execveat_syscall_kp = {
.symbol_name = SYS_EXECVEAT_SYMBOL,
.pre_handler = sys_execveat_handler_pre,
};

static struct kprobe compat_execve_syscall_kp = {
.symbol_name = COMPAT_SYS_EXECVE_SYMBOL,
.pre_handler = sys_execveat_handler_pre,
};

static struct kprobe compat_execveat_syscall_kp = {
.symbol_name = COMPAT_SYS_EXECVEAT_SYMBOL,
.pre_handler = sys_execveat_handler_pre,
};

static struct kprobe *execve_kps[] = {
&execve_syscall_kp, &compat_execve_syscall_kp,
&execveat_syscall_kp, &compat_execveat_syscall_kp
};

#else
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
.symbol_name = "do_execveat_common",
Expand All @@ -238,6 +299,7 @@ static struct kprobe execve_kp = {
#endif
.pre_handler = execve_handler_pre,
};
#endif

#endif

Expand All @@ -246,7 +308,11 @@ void ksu_sucompat_init()
{
#ifdef CONFIG_KPROBES
int ret;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
ret = register_kprobes(execve_kps, 4);
#else
ret = register_kprobe(&execve_kp);
#endif
pr_info("sucompat: execve_kp: %d\n", ret);
ret = register_kprobe(&newfstatat_kp);
pr_info("sucompat: newfstatat_kp: %d\n", ret);
Expand All @@ -257,7 +323,11 @@ void ksu_sucompat_init()

void ksu_sucompat_exit() {
#ifdef CONFIG_KPROBES
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
unregister_kprobes(execve_kps, 4);
#else
unregister_kprobe(&execve_kp);
#endif
unregister_kprobe(&newfstatat_kp);
unregister_kprobe(&faccessat_kp);
#endif
Expand Down

0 comments on commit 13568bb

Please sign in to comment.