考虑以下内核模块源代码,它用于kprobes_register
获取内核符号的地址。
它适用于像这样的符号flush_tlb_all
,但不适用于sys_call_table
.
使用以下命令快速查找/proc/kallsyms
:
sudo cat /proc/kallsyms | grep -E '\sflush_tlb_all$|\ssys_call_table$'
ffffffff86a83e20 T flush_tlb_all
ffffffff87a002e0 D sys_call_table
区别在于 ( man nm
)flush_tlb_all
位于该text
部分中,而 assys_call_table
位于该data
部分中。然而,这两个符号都是全局的(外部的)。
为什么不能kprobes_register
用来查找 的地址sys_call_table
?
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#define MAX_SYMBOL_LEN 64
static char symbol[MAX_SYMBOL_LEN] = "flush_tlb_all";
module_param_string(symbol, symbol, sizeof(symbol), 0644);
/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
.symbol_name = symbol,
};
static int __init kprobe_init(void)
{
int ret;
ret = register_kprobe(&kp);
if (ret < 0) {
pr_err("register_kprobe failed, returned %d\n", ret);
return ret;
}
pr_info("Planted kprobe at %p\n", kp.addr);
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
pr_info("kprobe at %p unregistered\n", kp.addr);
}
module_init(kprobe_init);
module_exit(kprobe_exit);
MODULE_LICENSE("GPL");
答案1
区别在于 (
man nm
)flush_tlb_all
位于该text
部分中,而 assys_call_table
位于该data
部分中。然而,这两个符号都是全局的(外部的)。
这正是register_kprobe
失败的原因sys_call_table
:它只允许在内核文本中进行探测。kprobe_register
来电check_kprobe_address_safe
一旦它有了要探测的地址,后者就会检查该地址是否是内核文本的一部分。