Linux

為什麼 kprobes_register (kprobes) 能夠檢索 flush_tlb_all 等符號的符號地址,但不能檢索 sys_call_table

  • April 29, 2021

考慮以下核心模組原始碼,它用於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_tabledata節中。但是,這兩個符號都是全域的(外部的)。

為什麼不能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");

不同之處在於 ( man nm)flush_tlb_all是在text節中,而 assys_call_tabledata節中。但是,這兩個符號都是全域的(外部的)。

這正是register_kprobe失敗的原因sys_call_table:它只允許在核心文本中進行探測。kprobe_register一旦它有要探測的地址就呼叫check_kprobe_address_safe,後者檢查地址是否是核心文本的一部分。

引用自:https://unix.stackexchange.com/questions/643206