kprobes中未定义异常处理程序(__und_svc)的作用是什么?

4

我试图将kprobe转换为可加载的内核模块。

我能够运行内核树中samples/kprobes/文件夹中提供的示例。

如果我们在内核中配置了kprobes(CONFIG_KPROBES),那么__und_svc()处理程序中的svc_entry宏将扩展为64字节。

参考: http://lxr.free-electrons.com/source/arch/arm/kernel/entry-armv.S?a=arm#L245

我的目标是不触及内核端,在不启用CONFIG_KPROBES的情况下,将kprobe作为内核模块。

因此,内核编译时没有启用CONFIG_KPROBES。所以在__und_svc()中,svc_entry宏将扩展为0。

我想要解决以下疑问:

  1. 如果kprobe处理未定义指令异常(因为只有kprobe被创建),那么为什么会调用__und_svc()__und_svc()处理程序在kprobes方面的作用是什么?

  2. 如果64字节内存是必需的,那么如何在不编译内核的情况下分配它?即如何动态完成?

请分享您的知识。


虽然我喜欢在SO上看到精确的问题,但我担心这个问题太具体了。你是否也尝试过与内核相关的邮件列表? - Andrejs Cainikovs
是的。我在systemtap邮件列表和linux-arm邮件列表上都发布了这个问题。不幸的是,在linux-arm上它还没有发布。 - Jeyaram
1个回答

5
您可能无法获得回复,因为您对事物的理解不是非常好,而且任何在 linux-arm-kernel 列表中的人都需要一些时间来回复。请阅读 kprobes.txt 并详细研究 ARM 架构。

如果 kprobe 处理未定义指令异常(因为只有创建了 kprobe),那么为什么会调用 __und_svc()。就 kprobe 而言,__und_svc() 处理程序的作用是什么?

在 ARM 上,模式 0b11011未定义指令模式。当发生未定义指令时的流程如下:
  1. lr_und = 未定义指令的 pc + 4
  2. SPSR_und = 发生指令的模式的 CPSR。
  3. 切换到禁用中断的 ARM 模式。
  4. PC = 向量基址 + 4
第四步的主向量表位于__vectors_start,它只是跳转到vector_und。代码是一个名为vector_stub的宏,它决定是调用__und_svc还是__und_usr。堆栈是每个进程保留的 4/8k 页面。它是包含任务结构和内核堆栈的内核页面。

kprobe通过在您希望探测的代码地址处放置未定义指令来工作。也就是说,它涉及未定义指令处理程序。这应该很明显。它调用两个例程call_fpedo_undefinstr()。您感兴趣的是第二种情况,它获取操作码并调用call_undef_hook()。使用register_undef_hook()添加钩子;您可以在arch_init_kprobes()中看到。主回调kprobe_handler使用一个struct pt_regs *regs调用,这恰好是在__und_svc中保留的额外内存。请注意例如kretprobe_trampoline(),它正在与当前执行的堆栈玩弄。

如果64字节的内存是必需的,则如何在不编译内核的情况下进行分配。即如何动态执行它?

不,不是这样。您可以使用不同的机制,但可能需要修改kprobes代码。最有可能的是您将不得不限制功能。完全重写堆栈帧并在事后保留额外的64字节也是可能的。这不是像kmalloc()那样的分配。它只是从监管者堆栈指针添加/减去一个数字。我猜测该代码会将未定义处理程序的返回地址重新编写为在kprobed地址的上下文(ISR、底半部/线程IRQ、work_queue、内核任务)中执行。但是可能还存在其他问题,您尚未遇到。如果永远不调用arch_init_kprobes(),则可以在__und_svc中始终进行预留;它只会消耗64字节的堆栈,这将使内核堆栈溢出的可能性更大。也就是说,改变:

__und_svc:
    @ Always reserve 64 bytes, even if kprobe is not active.
    svc_entry 64

arch_init_kprobes()是实际安装该功能的函数。


感谢您对call_undef_hook()相关内容的启发。这更加详细了解了此事。但是我无法更改entry-armv.S中的__und_svc()。在提交d30a0c8bf99f0e6a7d8c57bd4524039585ffbced中,只添加了这64个字节。因此,我正在尝试理解他们添加了哪个功能/错误修复。 - Jeyaram
只需打补丁您的内核。在 entry-armv.S 中,使用调整任务的代码设置 svc_entry,然后始终使用 svc_entry 64。您不需要拉取完整的补丁集。git diff d30a0c8bf99~1..d30a0c8bf99 给我一个完整的补丁。您可以保存它并运行 echo svc_entry.patch | patch -p1。或者您是在问是否可以不重新编译内核并修复此问题?这几乎是不可能的;您必须重新编写所有的 arm/kernel/kprobes.c 代码。 - artless noise
我的要求是在不对内核应用任何补丁甚至一点更改的情况下,将kprobes修改为LKM。因此,我别无选择,只能重写arm/kernel/kprobes.c文件。 - Jeyaram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接