From 770c9632aeca079f141691addaa4e6f3036eb5b9 Mon Sep 17 00:00:00 2001 From: liankong Date: Sun, 30 Mar 2025 16:52:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0panic=E6=97=B6=E6=89=93?= =?UTF-8?q?=E5=8D=B0=E5=87=BA=E5=AF=B9=E5=BA=94KPM=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/core_hook.c | 2 + kernel/kpm/compact.c | 36 ++++++++++--- kernel/kpm/kpm.c | 122 ++++++++++++++++++++++++++++++++----------- kernel/kpm/kpm.h | 2 + 4 files changed, 126 insertions(+), 36 deletions(-) diff --git a/kernel/core_hook.c b/kernel/core_hook.c index ea424703..abf76057 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -688,6 +688,7 @@ __maybe_unused int ksu_kprobe_init(void) #ifdef CONFIG_KPM kpm_cfi_bypass_init(); + kpm_stack_init(); #endif return rc; @@ -699,6 +700,7 @@ __maybe_unused int ksu_kprobe_exit(void) unregister_kprobe(&renameat_kp); #ifdef CONFIG_KPM kpm_cfi_bypass_exit(); + kpm_stack_exit(); #endif return 0; } diff --git a/kernel/kpm/compact.c b/kernel/kpm/compact.c index 61e99a35..40d26377 100644 --- a/kernel/kpm/compact.c +++ b/kernel/kpm/compact.c @@ -43,6 +43,12 @@ struct CompactAliasSymbol { const char* compact_symbol_name; }; +struct CompactProxySymbol { + const char* symbol_name; + const char* compact_symbol_name; + void* cached_address; +}; + struct CompactAddressSymbol address_symbol [] = { { "kallsyms_lookup_name", &kallsyms_lookup_name }, { "compact_find_symbol", &sukisu_compact_find_symbol }, @@ -53,12 +59,31 @@ struct CompactAddressSymbol address_symbol [] = { }; struct CompactAliasSymbol alias_symbol[] = { - {"kf_strncat", "strncat"}, - {"kf_strlen", "strlen" }, - {"kf_strcpy", "strcpy"}, {"compat_copy_to_user", "__arch_copy_to_user"} }; +struct CompactProxySymbol proxy_symbol[] = { + {"kf_strncat", "strncat", NULL }, + {"kf_strlen", "strlen", NULL }, + {"kf_strcpy", "strcpy", NULL }, +}; + +static unsigned long sukisu_find_proxy_symbol(const char* name) { + // 查不到就查查兼容的符号 + for(i = 0; i < (sizeof(proxy_symbol) / sizeof(struct CompactProxySymbol)); i++) { + struct CompactProxySymbol* symbol = &alias_symbol[i]; + if(strcmp(name, symbol->symbol_name) == 0) { + if(symbol->cached_address == NULL) { + symbol->cached_address = kallsyms_lookup_name(name); + } + if(symbol->cached_address != NULL) { + return (unsigned long) &symbol->cached_address; + } + } + } + return 0; +} + unsigned long sukisu_compact_find_symbol(const char* name) { int i; unsigned long addr; @@ -73,9 +98,8 @@ unsigned long sukisu_compact_find_symbol(const char* name) { /* 如果符号名以 "kf__" 开头,尝试解析去掉前缀的部分 */ if (strncmp(name, "kf__", 4) == 0) { - const char *real_name = name + 4; // 去掉 "kf__" - addr = (unsigned long)kallsyms_lookup_name(real_name); - if (addr) { + addr = sukisu_find_proxy_symbol(name); + if(addr != 0) { return addr; } } diff --git a/kernel/kpm/kpm.c b/kernel/kpm/kpm.c index e714a920..a703466d 100644 --- a/kernel/kpm/kpm.c +++ b/kernel/kpm/kpm.c @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include "kpm.h" #include "compact.h" @@ -1100,36 +1103,6 @@ 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 >= start_address && addr <= end_address) { - allow = true; - break; - } - } - spin_unlock(&kpm_module_lock); - - // TODO: 增加Hook跳板放行机制 - - return allow; -} - /*----------------------------------------------------------- * 模块管理查询接口 *----------------------------------------------------------*/ @@ -1266,6 +1239,95 @@ EXPORT_SYMBOL(sukisu_kpm_load_module_path); EXPORT_SYMBOL(sukisu_kpm_unload_module); EXPORT_SYMBOL(sukisu_kpm_find_module); +// =========================================================================================== + +/*--------------------- 地址过滤逻辑 ---------------------*/ +/** + * 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 >= start_address && addr <= end_address) { + allow = true; + break; + } + } + spin_unlock(&kpm_module_lock); + + // TODO: 增加Hook跳板放行机制 + + return allow; +} + +static struct kprobe dump_stack_kp = { + .symbol_name = "dump_stack", +}; + +static int handler_dump_stack_pre(struct kprobe *p, struct pt_regs *regs) +{ + struct stack_trace trace = { + .nr_entries = 0, + .max_entries = 32, + .entries = (unsigned long *)kmalloc(32*sizeof(unsigned long), GFP_ATOMIC), + }; + int i; + + /* 捕获当前调用栈 */ + save_stack_trace(&trace); + + /* 遍历栈地址并匹配 KPM 模块 */ + printk(KERN_EMERG "KPM Stack Trace:\n"); + for (i = 0; i < trace.nr_entries; i++) { + struct kpm_module *pos; + unsigned long addr = trace.entries[i]; + + 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 >= start_address && addr <= end_address) { + printk(KERN_EMERG "[KPM: <%px>] %s+%px\n", + (void *)addr, pos->info.name, addr - ((unsigned long)pos->start)); + break; + } + } + } + + kfree(trace.entries); + return 0; // 继续执行原始 dump_stack +} + +/* 模块初始化 */ +int kpm_stack_init(void) +{ + int ret; + if ((ret = register_kprobe(&dump_stack_kp)) < 0) { + printk(KERN_ERR "Failed to hook dump_stack: %d\n", ret); + return ret; + } + dump_stack_kp.pre_handler = handler_dump_stack_pre; + return 0; +} + +/* 模块卸载 */ +void kpm_stack_exit(void) +{ + unregister_kprobe(&dump_stack_kp); +} + // ============================================================================================ int sukisu_handle_kpm(unsigned long arg3, unsigned long arg4, unsigned long arg5) diff --git a/kernel/kpm/kpm.h b/kernel/kpm/kpm.h index 0203393d..3d0deae3 100644 --- a/kernel/kpm/kpm.h +++ b/kernel/kpm/kpm.h @@ -6,6 +6,8 @@ int sukisu_is_kpm_control_code(unsigned long arg2); int kpm_cfi_bypass_init(void); void kpm_cfi_bypass_exit(void); +int kpm_stack_init(void); +void kpm_stack_exit(void); // KPM控制代码 #define CMD_KPM_CONTROL 28