我正在尝试在arm64 linux5.7中挂钩一些内核函数,例如kmem_cache_alloc(这个版本在arm64中有CONFIG_DYNAMIC_FTRACE_WITH_REGS)。但我在调用函数时总是进入无限循环。
所以我简化了代码并编写了一个演示来挂钩下面的 _do_fork,在 x86-64 上代码很好并且应该停止循环的部分工作正常。一个小细节是 ftrace_set_filter_ip 在arm64中不起作用,但 ftrace_set_filter 工作得很好。
asmlinkage long (*original_do_fork)(unsigned long clone_flags,...);
asmlinkage long hooked_do_fork(unsigned long clone_flags, unsigned long stack_start,
unsigned long stack_size, int __user *parent_tidptr,
int __user *child_tidptr, unsigned long tls) {
printk("hooked_do_fork called!\n");
return original_do_fork(clone_flags, stack_start, stack_size, parent_tidptr, child_tidptr, tls);
}
// fh_ftrace_thunk
static void notrace fh_ftrace_thunk(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *ops, struct pt_regs *regs) {
printk("fh_ftrace_thunk called!\n");
struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops);
//this should stop infinite loop but not working
if (!within_module(parent_ip, THIS_MODULE)) regs->pc = (unsigned long)hook->function;
}
static int __init fh_init(void) {
hook.address = kallsyms_lookup_name(hook.name);
*((unsigned long*)&original_do_fork) = hook.address+ MCOUNT_INSN_SIZE;
hook.ops.func = fh_ftrace_thunk;
hook.ops.flags = FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED | FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_IPMODIFY;
err = ftrace_set_filter(&hook.ops, hook.name, strlen(hook.name), 0);
err = register_ftrace_function(&hook.ops);
return 0;
}
输出如下:
[ 26.788937] fh_ftrace_thunk called!
[ 26.789224] fh_ftrace_thunk called!
[ 26.789544] fh_ftrace_thunk called!
[ 26.789788] fh_ftrace_thunk called!
[ 26.790090] fh_ftrace_thunk called!
[ 26.790314] fh_ftrace_thunk called!
[ 26.790600] fh_ftrace_thunk called!
[ 26.790866] fh_ftrace_thunk called!
[ 26.791429] fh_ftrace_thunk called!
[ 26.791661] fh_ftrace_thunk called!
[ 26.800664] fh_ftrace_thunk called!
[ 26.801035] fh_ftrace_thunk called!
[ 26.801426] fh_ftrace_thunk called!
是什么导致了这个无限循环?我是否遗漏了任何 arm64 详细信息?
通过删除
printk("fh_ftrace_thunk called!\n");
.
并改变
*((unsigned long*)&original_do_fork) = hook.address+MCOUNT_INSN_SIZE;
到
*((unsigned long*)&original_do_fork) = hook.address;
我解决了上面的问题,但仍然不知道这是如何工作的。