diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 2f2c090c..ea424703 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -686,6 +686,10 @@ __maybe_unused int ksu_kprobe_init(void) rc = register_kprobe(&renameat_kp); pr_info("renameat kp: %d\n", rc); + #ifdef CONFIG_KPM + kpm_cfi_bypass_init(); + #endif + return rc; } @@ -693,6 +697,9 @@ __maybe_unused int ksu_kprobe_exit(void) { unregister_kprobe(&prctl_kp); unregister_kprobe(&renameat_kp); + #ifdef CONFIG_KPM + kpm_cfi_bypass_exit(); + #endif return 0; } diff --git a/kernel/kpm/bypasscfi.c b/kernel/kpm/bypasscfi.c new file mode 100644 index 00000000..223e54cc --- /dev/null +++ b/kernel/kpm/bypasscfi.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +/* CFI 检查函数符号 */ +#define CFI_CHECK_FUNC "__cfi_check" + +/* Kprobe 实例 */ +static struct kprobe cfi_kp; + +bool kpm_is_allow_address(unsigned long addr); + +/*--------------------- kprobe 处理逻辑 ---------------------*/ +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long target_addr; + + /* 从寄存器获取目标地址(架构相关) */ +#if defined(__aarch64__) + target_addr = regs->regs[1]; // ARM64: 第二个参数在 X1 +#elif defined(__x86_64__) + target_addr = regs->si; // x86_64: 第二个参数在 RSI +#else + #error "Unsupported architecture" +#endif + + /* 根据自定义规则放行 */ + if (kpm_is_allow_address(target_addr)) { + printk(KERN_INFO "CFI bypass at 0x%lx\n", target_addr); +#if defined(__aarch64__) + regs->regs[0] = 0; // 修改返回值:0 表示校验通过 +#elif defined(__x86_64__) + regs->ax = 0; // x86 返回值在 RAX +#endif + return 0; // 跳过原始 CFI 检查 + } + + return 0; // 继续执行原始检查 +} + +/*--------------------- 模块初始化/卸载 ---------------------*/ +int kpm_cfi_bypass_init(void) +{ + unsigned long cfi_check_addr; + + /* 动态查找 CFI 检查函数 */ + cfi_check_addr = kallsyms_lookup_name(CFI_CHECK_FUNC); + if (!cfi_check_addr) { + printk(KERN_ERR "CFI check function not found\n"); + return -ENOENT; + } + + /* 初始化 kprobe */ + memset(&cfi_kp, 0, sizeof(cfi_kp)); + cfi_kp.addr = (kprobe_opcode_t *)cfi_check_addr; + cfi_kp.pre_handler = handler_pre; + + /* 注册 kprobe */ + if (register_kprobe(&cfi_kp) < 0) { + printk(KERN_ERR "Register kprobe failed\n"); + return -EINVAL; + } + + printk(KERN_INFO "CFI bypass module loaded\n"); + return 0; +} + +void kpm_cfi_bypass_exit(void) +{ + unregister_kprobe(&cfi_kp); + printk(KERN_INFO "CFI bypass module unloaded\n"); +} diff --git a/kernel/kpm/kpm.c b/kernel/kpm/kpm.c index 45b029ac..f635ff64 100644 --- a/kernel/kpm/kpm.c +++ b/kernel/kpm/kpm.c @@ -175,10 +175,10 @@ struct kpm_module { unsigned int size; /* 总大小 */ unsigned int text_size; unsigned int ro_size; - int (*init)(const char *args, const char *event, void *__user reserved) __nocfi; - void (*exit)(void *__user reserved) __nocfi; - int (*ctl0)(const char *ctl_args, char *__user out_msg, int outlen) __nocfi; - int (*ctl1)(void *a1, void *a2, void *a3) __nocfi; + int (*init)(const char *args, const char *event, void *__user reserved); + void (*exit)(void *__user reserved); + int (*ctl0)(const char *ctl_args, char *__user out_msg, int outlen); + int (*ctl1)(void *a1, void *a2, void *a3); struct { const char *base; const char *name; @@ -937,6 +937,7 @@ static int kpm_setup_load_info(struct kpm_load_info *info) * KPM 模块加载主流程 *----------------------------------------------------------*/ /* 注意:接口名称改为 kpm_load_module,避免与内核原有 load_module 冲突 */ +__nocfi long kpm_load_module(const void *data, int len, const char *args, const char *event, void *__user reserved) { @@ -1025,6 +1026,7 @@ out: } /* 卸载模块接口,改名为 sukisu_kpm_unload_module */ +__nocfi long sukisu_kpm_unload_module(const char *name, void *__user reserved) { long rc = 0; @@ -1098,6 +1100,36 @@ free_data: return rc; } +/*--------------------- 地址过滤逻辑 ---------------------*/ +/** + * is_allow_address - 自定义地址放行规则 + * @addr: 目标函数地址 + * + * 返回值: true 放行 | false 拦截 + */ +bool kpm_is_allow_address(unsigned long addr) +{ + struct kpm_module *pos; + bool allow = false; + + spin_lock(&kpm_module_lock); + list_for_each_entry(pos, &kpm_module_list, list) { + unsigned long start_address = (unsigned long) pos->start; + unsigned long end_address = start_address + pos->size; + + /* 规则1:地址在KPM允许范围内 */ + if (addr >= allow_start && addr <= allow_end) { + allow = true; + break; + } + } + spin_unlock(&kpm_module_lock); + + // TODO: 增加Hook跳板放行机制 + + return allow; +} + /*----------------------------------------------------------- * 模块管理查询接口 *----------------------------------------------------------*/ diff --git a/kernel/kpm/kpm.h b/kernel/kpm/kpm.h index cb1e03ab..0203393d 100644 --- a/kernel/kpm/kpm.h +++ b/kernel/kpm/kpm.h @@ -4,6 +4,9 @@ int sukisu_handle_kpm(unsigned long arg3, unsigned long arg4, unsigned long arg5); int sukisu_is_kpm_control_code(unsigned long arg2); +int kpm_cfi_bypass_init(void); +void kpm_cfi_bypass_exit(void); + // KPM控制代码 #define CMD_KPM_CONTROL 28 #define CMD_KPM_CONTROL_MAX 34