1

使用内核模块 (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不再涉及。我如何告诉内核不要重置当前寄存器,以便函数可以在新的返回地址处使用它们?

4

1 回答 1

0

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

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;
}

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

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

于 2017-03-23T05:42:44.990 回答