【问题标题】:restoring task pt_regs when returning to original function from ftrace handler从 ftrace 处理程序返回到原始函数时恢复任务 pt_regs
【发布时间】:2017-03-23 03:04:46
【问题描述】:

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

【问题讨论】:

    标签: linux-kernel ftrace


    【解决方案1】:

    发布此消息后,我想到也许我可以直接从 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 是另一个检查从regs->di 寄存器读取的bprm->file 的函数。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-17
      • 2011-10-11
      • 2020-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多