添加跳过CFI检查的机制
This commit is contained in:
@@ -686,6 +686,10 @@ __maybe_unused int ksu_kprobe_init(void)
|
|||||||
rc = register_kprobe(&renameat_kp);
|
rc = register_kprobe(&renameat_kp);
|
||||||
pr_info("renameat kp: %d\n", rc);
|
pr_info("renameat kp: %d\n", rc);
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPM
|
||||||
|
kpm_cfi_bypass_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,6 +697,9 @@ __maybe_unused int ksu_kprobe_exit(void)
|
|||||||
{
|
{
|
||||||
unregister_kprobe(&prctl_kp);
|
unregister_kprobe(&prctl_kp);
|
||||||
unregister_kprobe(&renameat_kp);
|
unregister_kprobe(&renameat_kp);
|
||||||
|
#ifdef CONFIG_KPM
|
||||||
|
kpm_cfi_bypass_exit();
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
73
kernel/kpm/bypasscfi.c
Normal file
73
kernel/kpm/bypasscfi.c
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/kallsyms.h>
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
}
|
||||||
@@ -175,10 +175,10 @@ struct kpm_module {
|
|||||||
unsigned int size; /* 总大小 */
|
unsigned int size; /* 总大小 */
|
||||||
unsigned int text_size;
|
unsigned int text_size;
|
||||||
unsigned int ro_size;
|
unsigned int ro_size;
|
||||||
int (*init)(const char *args, const char *event, void *__user reserved) __nocfi;
|
int (*init)(const char *args, const char *event, void *__user reserved);
|
||||||
void (*exit)(void *__user reserved) __nocfi;
|
void (*exit)(void *__user reserved);
|
||||||
int (*ctl0)(const char *ctl_args, char *__user out_msg, int outlen) __nocfi;
|
int (*ctl0)(const char *ctl_args, char *__user out_msg, int outlen);
|
||||||
int (*ctl1)(void *a1, void *a2, void *a3) __nocfi;
|
int (*ctl1)(void *a1, void *a2, void *a3);
|
||||||
struct {
|
struct {
|
||||||
const char *base;
|
const char *base;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -937,6 +937,7 @@ static int kpm_setup_load_info(struct kpm_load_info *info)
|
|||||||
* KPM 模块加载主流程
|
* KPM 模块加载主流程
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
/* 注意:接口名称改为 kpm_load_module,避免与内核原有 load_module 冲突 */
|
/* 注意:接口名称改为 kpm_load_module,避免与内核原有 load_module 冲突 */
|
||||||
|
__nocfi
|
||||||
long kpm_load_module(const void *data, int len, const char *args,
|
long kpm_load_module(const void *data, int len, const char *args,
|
||||||
const char *event, void *__user reserved)
|
const char *event, void *__user reserved)
|
||||||
{
|
{
|
||||||
@@ -1025,6 +1026,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 卸载模块接口,改名为 sukisu_kpm_unload_module */
|
/* 卸载模块接口,改名为 sukisu_kpm_unload_module */
|
||||||
|
__nocfi
|
||||||
long sukisu_kpm_unload_module(const char *name, void *__user reserved)
|
long sukisu_kpm_unload_module(const char *name, void *__user reserved)
|
||||||
{
|
{
|
||||||
long rc = 0;
|
long rc = 0;
|
||||||
@@ -1098,6 +1100,36 @@ free_data:
|
|||||||
return rc;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* 模块管理查询接口
|
* 模块管理查询接口
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
int sukisu_handle_kpm(unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
int sukisu_handle_kpm(unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
||||||
int sukisu_is_kpm_control_code(unsigned long arg2);
|
int sukisu_is_kpm_control_code(unsigned long arg2);
|
||||||
|
|
||||||
|
int kpm_cfi_bypass_init(void);
|
||||||
|
void kpm_cfi_bypass_exit(void);
|
||||||
|
|
||||||
// KPM控制代码
|
// KPM控制代码
|
||||||
#define CMD_KPM_CONTROL 28
|
#define CMD_KPM_CONTROL 28
|
||||||
#define CMD_KPM_CONTROL_MAX 34
|
#define CMD_KPM_CONTROL_MAX 34
|
||||||
|
|||||||
Reference in New Issue
Block a user