ebpf

How to get payload data from tcp_probe tracepoint via ebpf?


I need to read the payload of TCP packets. The following code always print an empty payload, even though payloadSize is greater than zero. What am I doing wrong?

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

struct data_t {
      unsigned pid;
      unsigned uid;
      unsigned short sport;
      unsigned short dport;
      int payloadSize;
      char payload[256];
};

SEC("tp/tcp/tcp_probe")
int trace_http2_headers(struct trace_event_raw_tcp_probe *ctx) {
   struct data_t data = {};
   data.pid = bpf_get_current_pid_tgid() >> 32;
   data.uid = bpf_get_current_uid_gid() >> 32;
  bpf_probe_read(&data.sport, sizeof(data.sport),&ctx->sport);
  bpf_probe_read(&data.dport, sizeof(data.dport),&ctx->dport);
  bpf_probe_read(&data.payloadSize, sizeof(data.payloadSize),&ctx->data_len);

  bpf_probe_read(&data.payload, 256 * sizeof(char), ctx->__data);
    
 if (data.payloadSize ==0) return 0;
 bpf_printk("PAYLOAD: %.*s\n", data.payloadSize, data.payload);

  return 0;
}

char LICENSE[] SEC("license") = "Dual BSD/GPL"; 

Solution

  • TL;DR. Your code is probably not showing anything because the syntax %.*s isn't supported by the bpf_trace_printk helper.


    Sources

    From the documentation:

    The conversion specifiers supported by fmt are similar, but more limited than for printk(). They are %d, %i, %u, %x, %ld, %li, %lu, %lx, %lld, %lli, %llu, %llx, %p, %s. No modifier (size of field, padding with zeroes, etc.) is available, and the helper will return -EINVAL (but print nothing) if it encounters an unknown specifier.


    Testing

    If I run the following program with bcc:

    char payload[10] = "Tail-call";
    int res = bpf_trace_printk("PAYLOAD: %.*s", payload);
    if (res < 0) {
        bpf_trace_printk("The first call to bpf_trace_printk failed.");
    }
    return 0;
    

    Then bcc warns me about my incorrect specifier and the first printk call then fails:

    $ sudo python3 examples/hello_world.py 
    /virtual/main.c:4:42: warning: only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed
        int res = bpf_trace_printk("PAYLOAD: %.*s", payload);
                                             ^
    1 warning generated.
    b' gnome-terminal--7331    [003] ...21  1095.386386: bpf_trace_printk: The first call to bpf_trace_printk failed.'
    b' gnome-terminal--7896    [004] ...21  1095.395751: bpf_trace_printk: The first call to bpf_trace_printk failed.'
    b'            bash-7898    [002] ...21  1095.396742: bpf_trace_printk: The first call to bpf_trace_printk failed.'