Kendrick
Kendrick

Reputation: 1

eBPF reserve ring buffer in kprobe and submit in kretprobe

I want to use eBPF to trace the success syscalls with high performance. Specifically, I allocate memory in the entry of syscall (hooked by kprobe) by ringbuf_reserve and store the pointer on a map. Then, in the return of the syscall (hooked by kretprobe), I get the pointer and do ringbuf_submit/ringbuf_discard according to the return value of this syscall.

However, I got this eBPF error:

Unreleased reference id=3 alloc_insn=9
processed 263 insns (limit 1000000) max_states_per_insn 0 total_states 22 peak_states 22 mark_read 20

Traceback (most recent call last):
  File "./kernel_trace.py", line 44, in <module>
    b.attach_kprobe(event="vfs_unlink", fn_name="trace_vfs_unlink")
  File "/usr/lib/python3/dist-packages/bcc-0.31.0+0b5be9bb-py3.8.egg/bcc/__init__.py", line 877, in attach_kprobe
  File "/usr/lib/python3/dist-packages/bcc-0.31.0+0b5be9bb-py3.8.egg/bcc/__init__.py", line 552, in load_func
Exception: Failed to load BPF program b'trace_vfs_unlink': Invalid argument

I guess this error is caused by eBPF not being aware the reserved ring buffer memory will be handled in kretprobe. Any idea to solve/bypass this? Thanks in advance.

Here is my code snippets

BPF_RINGBUF_OUTPUT(ring_buffer, 1024);

int trace_vfs_rename(struct pt_regs *ctx, struct renamedata *rd) {
    u64 pid_tgid = bpf_get_current_pid_tgid();
    u32 pid = pid_tgid >> 32;
    u32 tid = (u32)pid_tgid;

    /* Allocate the data structure in ring buffer */
    data_t *data = (data_t *)ring_buffer.ringbuf_reserve(sizeof(data_t));

    if (data == NULL) {
        return 0;
    }

   /* Fill the data structure, ignored here */

   /* Insert the data  ptr to map*/
    currdata.update(&tid, data);
    return 0;
}

int trace_return(struct pt_regs *ctx)
{
    data_t **data;
    u32 tid = (u32)bpf_get_current_pid_tgid();
    int ret = PT_REGS_RC(ctx);

    /* Get the ring buffer pointer from map */   
    data = currdata.lookup(&tid);
    if (data == 0)
        return 0;

    currdata.delete(&tid);

    /* Skip the failed function call */
    if (ret)
        return 0;

    /* Submit the successful syscalls */
    ring_buffer.ringbuf_submit(*data, sizeof(**data), 0);
    return 0;
}

Upvotes: 0

Views: 46

Answers (0)

Related Questions