为什么“kprobes_register”(kprobes)能够检索“flush_tlb_all”等符号的符号地址,但不能检索“sys_call_table”?

为什么“kprobes_register”(kprobes)能够检索“flush_tlb_all”等符号的符号地址,但不能检索“sys_call_table”?

考虑以下内核模块源代码,它用于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一旦它有了要探测的地址,后者就会检查该地址是否是内核文本的一部分。

相关内容