I'm trying to hook some kernel functions like kmem_cache_alloc in arm64 linux5.7(this version has CONFIG_DYNAMIC_FTRACE_WITH_REGS in arm64). But I always enters an infinite loop when the function is called.
So I simplify the code and write a demo to hook _do_fork below, at x86-64 the code is fine and the part that should stop looping works fine. A little detail is that ftrace_set_filter_ip is not working in arm64 but ftrace_set_filter works good.
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;
}
Outputs below:
[ 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!
What is causing this infinite loop? Are there any arm64 details I'm missing?
By removing printk("fh_ftrace_thunk called!\n");
.
And change
*((unsigned long*)&original_do_fork) = hook.address+MCOUNT_INSN_SIZE;
to
*((unsigned long*)&original_do_fork) = hook.address;
I solved the problem above, but still don't know how this works.