kprobe不能直接探测内核函数内部变量值,仅能在指定地址触发回调并提供寄存器快照;读取参数需依ABI从pt_regs提取,读取全局/静态变量需符号地址加probe_kernel_read安全访问。

不能直接“探测内核函数的内部变量值”——kprobe本身不提供变量符号解析能力,它只在指定地址(函数入口、某条指令)触发回调,并提供寄存器快照(struct pt_regs *)。所谓“读内部变量”,本质是:根据函数ABI从寄存器/栈中还原参数,或通过已知符号地址+偏移手动计算变量位置,再用安全接口读取。生产环境尤其需严守安全边界,避免panic或数据污染。
先确认目标变量是否可访问
内核函数中的局部变量存在于栈上,生命周期短暂、地址不固定,kprobe无法稳定获取;真正能可靠探测的是:
-
函数参数:按ABI存于寄存器(x86_64为%rdi~%r9,ARM64为x0~x7)或栈顶,可从
regs中提取 -
全局变量或静态变量:有固定内核符号地址,查
/proc/kallsyms确认导出状态(如grep ' ^vfs_stat$' /proc/kallsyms) -
结构体成员:若已知指针(如参数传入的
struct file *),可结合结构体定义和offsetof()计算偏移
从寄存器安全读取函数参数值
例如探测sys_openat(int dfd, const char __user *filename, int flags):
- x86_64下:
dfd在regs->di,flags在regs->dx,可直接打印整型值 -
filename是用户态地址,绝不可写printk("%s", (char *)regs->si)——会触发oops - 改用
probe_kernel_read():申请栈缓冲区(≤256字节),安全复制字符串并补\0
示例代码片段:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
probe_kernel_read(buf, (void *)regs->si, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
printk("openat: dfd=%ld, filename='%s', flags=0x%lx\n", regs->di, buf, regs->dx);
读取全局/静态变量需符号地址+安全访问
若要读nr_processes(当前进程数)这类全局变量:
- 先查地址:
grep ' nr_processes$' /proc/kallsyms,得到类似ffffffff81c01234 R nr_processes - 在kprobe handler中声明
extern unsigned long nr_processes;并取地址,或直接用数值地址(需__force转换) - 读取时仍建议用
probe_kernel_read()而非直接解引用,尤其在中断上下文
避开常见失败点(生产环境关键)
register_kprobe()返回-22(-EINVAL)最常因:
- 目标函数未导出符号:如
do_sys_open通常不导出,应换用sys_openat或__x64_sys_openat - 函数被编译器inline:用
objdump -t vmlinux | grep target_func确认符号存在;不存在则选更稳定的入口(如security_file_open) - 内核配置缺失:
CONFIG_KPROBES=y和CONFIG_KPROBE_EVENTS=y必须启用,否则静默失败










