我是eBPF的新手,我知道eBPF是事件驱动的,这意味着在注册钩点之后,钩子函数将在发生这种事件时被执行。所以我想知道程序怎么能跳到钩子函数?
发布于 2022-06-05 13:56:10
内核代码对BPF程序有一个显式调用。例如,我们可以检查Amazon ENA驱动程序中的XDP钩子
xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
if (!xdp_prog)
goto out;
verdict = bpf_prog_run_xdp(xdp_prog, xdp);它首先检查是否加载了BPF程序;也就是说,rx_ring->xdp_bpf_prog不是空的。然后以struct xdf_buff对象作为参数(此处命名为xdp )运行BPF程序。其余代码处理来自BPF程序的返回代码(verdict)。
您可以为所有BPF程序类型找到相同的逻辑。
发布于 2022-06-06 12:00:31
皮吉诺的回答很好。
作为补充,还有一些其他eBPF程序类型,您没有预定义的钩子和调用。例如,对内核中的每个函数都没有明确的调用,在内核中可以附加一个k探头。在这种情况下,可能有一些不同的机制在发挥作用:
当注册一个k探针时,K探针会复制被探测的指令,并将被探测指令的第一个字节替换为断点指令(例如,int3 on i386和x86_64)。
此断点用于将CPU重定向到探测- 这里有更多的细节。这也是在BPF程序附加到k探针的情况下发生的情况。
发布于 2022-06-09 21:03:43
(很好的答案:)作为对重新探测的补充:就像前面说过的那样,它们也可以用int3 (在x86上)代替指令;用gdb来观察是很好的。但是,它们在函数开始时就这样做了;调用的蹦床替换了返回地址。您可以很容易地在一个小的测试程序中看到这一点,它会打印带有或不使用重探针的堆栈。您会注意到堆栈无法正确读取(至少由backtrace(...)读取)。
通常情况下,复测会很好。但是,请记住,它们篡改堆栈(以一种意外的方式)。至少在使用g++时,当被探测的被调用方引发在调用方中处理的异常时,它们会中断异常处理。
https://stackoverflow.com/questions/72507777
复制相似问题