所以我有这些宏
#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)
宏
PT_REGS_PARM1(x)
中的PARM
代表"参数"。这些宏允许您访问kprobe或跟踪点所挂接的函数的参数。因此,例如,PT_REGS_PARM1(ctx)
,其中ctx
是作为参数传递给eBPF程序的struct pt_regs *ctx
上下文,将允许您访问第一个参数(即文件描述符fd
(。类似地,PT_REGS_PARM3(ctx)
将为您提供count
,您可以通过查看此内核示例(write_size
(来确认这一点。
。。。但是使用bpf_probe_read_*()
来保持内核内存的安全
类似地,您可以使用PT_REGS_PARM2(ctx)
指向缓冲区buf
。然而,这是一个指针;如果您想操作这个缓冲区中包含的数据,您需要另一个步骤,否则内核可能会以不安全为由拒绝您的程序。要从这个缓冲区读取和复制部分或全部数据,您应该使用eBPF助手bpf_probe_read_*(void *dst, u32 size, const void *unsafe_ptr)
之一(请参阅相关文档(。在您的情况下,该缓冲区中包含的数据来自用户空间,因此您需要bpf_probe_read_user()
。
关于CO-RE的说明
这并不适用于您的示例,因为您的指针只是一个缓冲区。但是,如果其中一个参数是指向结构的指针,则需要类似的预防措施来取消引用它并访问它的字段。
在这种情况下,您可能希望利用CO-RE,以确保在读取字段时访问正确的偏移量。如果您有CO-RE支持,libbpf还提供了eBPF助手周围的bpf_core_read*()
包装器,这使得访问是可重定位的。有关更多信息,请参阅BPF CO-RE参考指南。
还有CO-RE(从技术上讲,这次只是BTF(,某些类型的跟踪程序,特别是BPF_PROG_TYPE_TRACING
,允许您在没有任何助手的情况下访问结构字段(请参阅CO-RE的最初文章(。