从ftrace处理程序

时间:2017-03-23 03:04:46

标签: linux-kernel ftrace

使用内核模块(LKM),linux内核ftrace函数允许您设置FTRACE_OPS_FL_SAVE_REGSFTRACE_OPS_FL_IPMODIFY标志,实质上允许您完全重定向您可以找到的任何内核函数符号地址,如下所示:

static void notrace my_ftrace_handler(unsigned long ip, unsigned long parent_ip,
        struct ftrace_ops *fops, struct pt_regs *regs) {
    regs->ip = new_addr;
}

其中new_addr是新函数的地址。 kpatch工具使用此工具,但从不返回原始函数。

如果在new_addr指向的函数的末尾,我试试这个:

task_pt_regs(current)->ip = orig_addr + MCOUNT_INSN_SIZE;

某些功能可以顺利进行,但大多数会导致调用进程的段错误。

ftrace函数有内置代码,可以在返回到原始函数时恢复当前任务的pt_regs,这就是为什么我能够使用自己的函数并且没有参数一个问题。但是,在代码中的这一点上,ftrace不再涉及。如何告诉内核不要重置当前寄存器,这样它们可以被新返回地址的函数使用?

1 个答案:

答案 0 :(得分:0)

发布后我想到也许我可以直接从ftrace处理程序中的pt_regs *regs指针读取参数。事实证明,你可以。通过不重定向到另一个函数,你可以保留寄存器和返回地址,同时决定你是从那里返回那里还是其他地方:

int donotexec(void) {
        return -EACCES;
}

static void notrace my_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                    struct ftrace_ops *fops, struct pt_regs *regs) {

    struct linux_binprm *bprm = (struct linux_binprm *)regs->di;

    if (bprm->file)
            if (allowed_to_exec(bprm->file))
                    regs->ip = (unsigned long)donotexec;
}

此函数挂钩security_bprm_check,其中allowed_to_exec是另一个检查从bprm->file寄存器中读取的regs->di的函数。

这是依赖于arch的(请参阅pt_regs中的内核arch/x86/include/asm/ptrace.h结构),并且仅限于5个函数参数。