如何通过eBPF从tcp_probe追踪点获取TCP载荷?代码异常排查
问题原因及修复方案
核心问题
tp/tcp/tcp_probe 这个tracepoint默认不会捕获TCP数据包的载荷内容,即使data_len显示有载荷长度,__data指向的区域也没有实际的payload数据,导致你读出来的内容为空。
修复步骤
1. 配置tcp_probe捕获payload
内核默认的tcp_probe只记录TCP头部信息,需要手动配置让它携带载荷:
# 设置捕获的最大payload长度(比如256字节,和你的代码数组大小匹配) echo 'probe:tcp_probe data=$data len=256' > /sys/kernel/debug/tracing/events/tcp/tcp_probe/trigger
也可以通过sysfs直接调整:
echo 256 > /sys/kernel/debug/tracing/events/tcp/tcp_probe/data_size
2. 修正代码读取逻辑
你的代码存在越界风险,需要调整读取长度为payloadSize和数组容量的最小值,避免BPF程序被内核拒绝加载:
#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); // 计算安全的读取长度,防止数组越界 int copy_len = data.payloadSize > sizeof(data.payload) ? sizeof(data.payload) : data.payloadSize; if (copy_len > 0) { bpf_probe_read(&data.payload, copy_len, 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";
3. 备选方案:换用其他tracepoint
如果tcp_probe的配置过于繁琐,可以改用tcp/tcp_sendmsg或tcp/tcp_recvmsg,这两个tracepoint可以直接获取用户态的缓冲区数据,不过需要用bpf_probe_read_user读取用户态内存。
内容的提问来源于stack exchange,提问作者rdabra
相关产品推荐
相关产品推荐

