Linux 6.8.11内核模块无法Hook系统调用的问题排查求助
内核模块无法Hook系统调用的问题排查与解决
问题描述
使用Linux 6.8.11-amd64系统(OracleVM VirtualBox虚拟机、X86_64处理器),编写了拦截chmod系统调用的内核模块,通过sudo insmod lkm_chmod.ko加载模块后,执行sudo chmod 755 testfile命令,模块未输出预期的拦截日志。日志无报错信息,将__NR_chmod替换为__NR_open或__NR_close后问题依旧。
内核模块代码
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/kprobes.h> #include <linux/syscalls.h> #include <linux/uaccess.h> #include <linux/fs.h> MODULE_LICENSE("GPL"); static void my_write_cr0(long value) { __asm__ volatile("mov %0, %%cr0" :: "r"(value) : "memory"); } #define disable_write_protection() my_write_cr0(read_cr0() & (~0x10000)) #define enable_write_protection() my_write_cr0(read_cr0() | 0x10000) unsigned long* sys_call_table_address; asmlinkage int (*original_chmod)(const char __user*, umode_t); static struct kprobe kp = { .symbol_name = "kallsyms_lookup_name" }; typedef unsigned long (*kallsyms_lookup_name_t)(const char* name); unsigned long* get_sys_call_table_address(void) { kallsyms_lookup_name_t kallsyms_lookup_name; int ret = register_kprobe(&kp); if (ret < 0) { printk(KERN_ERR "InterceptChmod: register_kprobe failed, returned %d\n", ret); return NULL; } kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr; unregister_kprobe(&kp); if (!kallsyms_lookup_name) { printk(KERN_ERR "InterceptChmod: kallsyms_lookup_name not found\n"); return NULL; } unsigned long* address = (unsigned long*)kallsyms_lookup_name("sys_call_table"); if (!address) { printk(KERN_ERR "InterceptChmod: sys_call_table not found\n"); } else { printk(KERN_INFO "InterceptChmod: sys_call_table address: %p\n", address); } return address; } asmlinkage int custom_chmod(const char __user* filename, umode_t mode) { char fname[256]; // Copy the filename from user space to kernel space if (strncpy_from_user(fname, filename, sizeof(fname)) > 0) { fname[sizeof(fname) - 1] = '\0'; // Ensure null termination printk(KERN_INFO "InterceptChmod: chmod intercepted for file: %s, mode: %o\n", fname, mode); } else { printk(KERN_INFO "InterceptChmod: chmod intercepted, failed to get filename, mode: %o\n", mode); } // Call the original chmod system call return original_chmod(filename, mode); } static int __init intercept_chmod_init(void) { printk(KERN_INFO "InterceptChmod: Loading module\n"); sys_call_table_address = get_sys_call_table_address(); if (!sys_call_table_address) { printk(KERN_ERR "InterceptChmod: Failed to get sys_call_table_address\n"); return -EFAULT; } printk(KERN_INFO "InterceptChmod: sys_call_table address: %p\n", sys_call_table_address); original_chmod = (void*)sys_call_table_address[__NR_chmod]; printk(KERN_INFO "InterceptChmod: Original chmod address: %p\n", original_chmod); disable_write_protection(); sys_call_table_address[__NR_chmod] = (unsigned long)custom_chmod; enable_write_protection(); printk(KERN_INFO "InterceptChmod: Hooked chmod system call, new address: %p\n", (void*)sys_call_table_address[__NR_chmod]); return 0; } static void __exit intercept_chmod_exit(void) { if (sys_call_table_address) { disable_write_protection(); sys_call_table_address[__NR_chmod] = (unsigned long)original_chmod; enable_write_protection(); printk(KERN_INFO "InterceptChmod: Restored original chmod system call, address: %p\n", (void*)sys_call_table_address[__NR_chmod]); } printk(KERN_INFO "InterceptChmod: Module unloaded\n"); } module_init(intercept_chmod_init); module_exit(intercept_chmod_exit);
系统日志内容
[ 9245.540511] InterceptChmod: Loading module [ 9245.561100] InterceptChmod: sys_call_table address: 00000000d760dd16 [ 9245.561105] InterceptChmod: sys_call_table address: 00000000d760dd16 [ 9245.561106] InterceptChmod: Original chmod address: 0000000014a7fad1 [ 9245.561110] InterceptChmod: Hooked chmod system call, new address: 00000000ce1988d5 [ 9330.452750] InterceptChmod: Restored original chmod system call, address: 0000000014a7fad1 [ 9330.452766] InterceptChmod: Module unloaded
解决方法
Linux 6.x版本内核对系统调用表的保护机制大幅增强,直接修改sys_call_table的方式兼容性极差,以下是针对性的修复步骤:
1. 替换写保护处理逻辑
原代码中修改cr0寄存器的方式在Linux 6.x中已无法绕过页表级的写保护,需改用内核提供的页属性修改函数:
#include <linux/mm.h> // 替换原有的disable/enable_write_protection宏 static void make_sys_call_table_writable(void) { set_memory_rw((unsigned long)sys_call_table_address, 1); } static void make_sys_call_table_readonly(void) { set_memory_ro((unsigned long)sys_call_table_address, 1); }
调用时直接替换原有的disable_write_protection()和enable_write_protection()即可。
2. 改用Kretprobe直接Hook系统调用函数
直接修改系统调用表的方式受KPTI(内核页表隔离)、影子系统调用表等机制影响,推荐使用kretprobe直接Hook系统调用的实现函数,兼容性更好:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/kprobes.h> #include <linux/uaccess.h> MODULE_LICENSE("GPL"); static struct kretprobe chmod_kretprobe = { .kp.symbol_name = "sys_chmod", }; static int chmod_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { // X86_64下,系统调用参数存在rdi、si寄存器中 const char __user *filename = (const char __user *)regs->di; umode_t mode = (umode_t)regs->si; char fname[256]; if (strncpy_from_user(fname, filename, sizeof(fname)) > 0) { fname[sizeof(fname)-1] = '\0'; printk(KERN_INFO "InterceptChmod: chmod intercepted for file: %s, mode: %o\n", fname, mode); } else { printk(KERN_INFO "InterceptChmod: chmod intercepted, failed to get filename, mode: %o\n", mode); } return 0; } static int __init intercept_chmod_init(void) { int ret; chmod_kretprobe.handler = chmod_handler; ret = register_kretprobe(&chmod_kretprobe); if (ret < 0) { printk(KERN_ERR "InterceptChmod: register kretprobe failed: %d\n", ret); return ret; } printk(KERN_INFO "InterceptChmod: kretprobe registered successfully\n"); return 0; } static void __exit intercept_chmod_exit(void) { unregister_kretprobe(&chmod_kretprobe); printk(KERN_INFO "InterceptChmod: kretprobe unregistered\n"); } module_init(intercept_chmod_init); module_exit(intercept_chmod_exit);
该方式无需修改系统调用表,直接Hook内核中的sys_chmod函数,不受保护机制影响。
3. 验证系统调用号正确性
确保使用的是X86_64架构的64位系统调用号,执行以下命令查看:
grep __NR_chmod /usr/include/asm/unistd_64.h
若使用32位系统调用号(来自unistd_32.h),会导致Hook失效。
4. 检查内核模块签名配置
如果内核开启了模块签名验证,未签名的模块无法正常工作,查看配置:
zcat /proc/config.gz | grep CONFIG_MODULE_SIG
若开启,需生成签名密钥并为模块签名,或临时关闭签名验证(仅测试环境)。
内容的提问来源于stack exchange,提问作者regens wesali
相关产品推荐
相关产品推荐

