如何从函数中读取所有参数 - ebpf

how to read all parameters from a function - ebpf

所以我有这些宏

#define PT_REGS_PARM1(x) ((x)->di)
#define PT_REGS_PARM2(x) ((x)->si)
#define PT_REGS_PARM3(x) ((x)->dx)
#define PT_REGS_PARM4(x) ((x)->cx)
#define PT_REGS_PARM5(x) ((x)->r8)
#define PT_REGS_RET(x) ((x)->sp)
#define PT_REGS_FP(x) ((x)->bp)
#define PT_REGS_RC(x) ((x)->ax)
#define PT_REGS_SP(x) ((x)->sp)
#define PT_REGS_IP(x) ((x)->ip)

但是上面没有说如何从函数中获取具体参数说`__sys_write

将sys_write视为

 long sys_write(unsigned int fd, const char __user *buf,
              size_t count);

所以我需要缓冲区,我一直在尝试不同的宏,但不确定哪个能给我什么?

所以谁能澄清一下

如果我正在读取缓冲区,也将读取缓冲区,那么也需要计数,这样我的 ebpf 程序就可以加载并且不会出现越界访问错误。谁能告诉我

使用 PT_REGS_PARM*(x)

PARM in PT_REGS_PARM1(x) 代表“参数”。这些宏允许您访问您的 kprobe 或 tracepoint 挂钩到的函数的参数。因此,例如,PT_REGS_PARM1(ctx),其中 ctx 是作为参数传递给您的 eBPF 程序的 struct pt_regs *ctx 上下文, 将给出您访问第一个参数,它是文件描述符fd。同样,PT_REGS_PARM3(ctx) 会给你 count,你可以通过查看 this kernel sample (write_size).

来确认。

... 但是使用 bpf_probe_read_*() 来保证内核内存的安全

同样,你可以用PT_REGS_PARM2(ctx)指向缓冲区buf。但是,这是一个指针;如果你想操作这个缓冲区中包含的数据,你需要另一个步骤,否则内核可能会拒绝你的程序作为不安全的。要从此缓冲区读取和复制部分或全部数据,您应该使用 eBPF 助手之一 bpf_probe_read_*(void *dst, u32 size, const void *unsafe_ptr)(参见 relevant documentation)。在您的情况下,该缓冲区中包含的数据来自用户 space,因此您需要 bpf_probe_read_user().

关于 CO-RE

的注释

这并不真正适用于您的示例,因为您的指针只是一个缓冲区。但是,如果您的参数之一是指向结构的指针,您将需要类似的预防措施来取消引用它并访问它的字段。

在这种情况下,您可能希望利用 CO-RE,以确保在读取字段时可以访问正确的偏移量。如果您有 CO-RE 支持,libbpf 还提供 bpf_core_read*() 围绕 eBPF 帮助器的包装器,使访问可重定位。有关详细信息,请参阅 the BPF CO-RE reference guide

还有 CO-RE(从技术上讲,这次只是 BTF),用于跟踪程序的某些类型,特别是 BPF_PROG_TYPE_TRACING,允许您在没有任何帮助程序的情况下访问结构字段(参见 the initial CO-RE article).