Search code examples
cebpf

how to read all parameters from a function - ebpf


So I have these macros

#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)

But the above does not say how to get specific parameter from function say `__sys_write

consider sys_write as

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

so I need buffer, I have been trying different macros but not really sure which one giving me what?

So can anyone please clearify it

If will also read buffer if I am reading buffer then count needed too so my ebpf program get loaded and not give out of bounds access error. can anyone tell


Solution

  • Use the PT_REGS_PARM*(x) macros

    PARM in PT_REGS_PARM1(x) stands for “parameter”. These macros give you access to the parameters of the function on which your kprobe or tracepoint is hooking to. So for example, PT_REGS_PARM1(ctx), where ctx is the struct pt_regs *ctx context passed as an argument to your eBPF program, will give you access to the first parameter, which is the file descriptor fd. Similarly, PT_REGS_PARM3(ctx) will give you the count, as you can confirm by looking at this kernel sample (write_size).

    ... But use bpf_probe_read_*() to stay safe with kernel memory

    Similarly, you can point to the buffer buf with PT_REGS_PARM2(ctx). However, this one is a pointer; if you want to manipulate the data contained in this buffer, you need another step, or the kernel may reject your program as unsafe. To read and copy some or all of the data from this buffer, you should use one of the eBPF helpers bpf_probe_read_*(void *dst, u32 size, const void *unsafe_ptr) (see relevant documentation). In your case, the data contained in that buffer comes from user space, so you want bpf_probe_read_user().

    Notes on CO-RE

    This does not really apply to your example, because your pointer is just a buffer. But if one of your arguments were a pointer to a struct, you would need similar precautions to dereference it and access its fields.

    And in such case you might want to leverage CO-RE, to make sure that you would access the correct offsets when reading the fields. If you have CO-RE support, libbpf also provides bpf_core_read*() wrappers around the eBPF helpers, which make access relocatable. See the BPF CO-RE reference guide for more information.

    Also with CO-RE (technically, just BTF this time), certain types for tracing programs, in particular BPF_PROG_TYPE_TRACING, allow you to access struct fields without any helper (See the initial CO-RE article).