You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在eBPF程序中使用bpf_probe_read复制大长度数据的问题

问题解决:eBPF读取write系统调用缓冲区的内核验证器错误

针对你在5.4.119内核下遇到的两个验证器错误,下面是具体原因和修复方案:

错误原因分析

1. R2 invalid mem access 'inv'

这个错误是因为内核验证器无法确认你操作的内存指针(R2)的有效性。通常是因为你没有对bpf_map_lookup_elem的返回值做非空检查,验证器认为你可能访问了无效内存,因此拒绝加载程序。

2. invalid stack type R4 off=-24 access_size=1039

5.4内核的eBPF栈大小限制为512字节,你尝试在栈上存储1024字节的缓冲区,直接触发了栈溢出,验证器报错。

修复方案

核心思路是:用BPF_MAP_TYPE_PERCPU_ARRAY存储大缓冲区,严格遵守内核验证器的指针有效性规则,避免栈溢出。

1. 正确定义Per-CPU数组Map

首先定义包含缓冲区和长度的结构体,作为Map的元素类型:

#include <uapi/linux/bpf.h>
#include <linux/types.h>
#include <linux/syscalls.h>

// 存储write调用的用户缓冲区数据
struct write_records {
    char buf[1024];
    size_t actual_len;
};

// 定义Per-CPU数组Map,每个CPU单独占用一个元素
struct bpf_map_def SEC("maps") write_buf_map = {
    .type = BPF_MAP_TYPE_PERCPU_ARRAY,
    .key_size = sizeof(u32),
    .value_size = sizeof(struct write_records),
    .max_entries = 1, // 只需要一个索引即可,Per-CPU会自动隔离
};

2. 修正Tracepoint程序逻辑

在程序中必须先检查Map元素指针的有效性,再进行内存操作,同时避免使用栈存储大缓冲区:

SEC("tracepoint/syscalls/sys_enter_write")
int trace_write_enter(struct trace_event_raw_sys_enter *ctx) {
    // 从tracepoint上下文获取write的参数
    char __user *user_buf = (char __user *)ctx->args[1];
    size_t write_len = ctx->args[2];
    u32 map_key = 0;
    struct write_records *buf_data;

    // 获取Per-CPU数组的元素指针,必须检查非空
    buf_data = bpf_map_lookup_elem(&write_buf_map, &map_key);
    if (!buf_data) {
        return 0;
    }

    // 计算实际读取长度,不超过缓冲区最大容量1024
    size_t read_len = write_len > 1024 ? 1024 : write_len;

    // 读取用户态缓冲区到Per-CPU数组中
    bpf_probe_read(buf_data->buf, read_len, user_buf);
    buf_data->actual_len = read_len;

    // 后续可将数据发送到用户态(例如通过Perf Event Array)
    // ...

    return 0;
}

3. 移除__builtin_memset的替代方案

5.4内核对__builtin_memset的eBPF支持有限,且如果是为了初始化缓冲区,Per-CPU数组的内存默认会被初始化为0,无需手动调用memset。如果确实需要初始化,可通过循环赋值实现(但通常不需要)。

关键注意事项

  • 5.4内核中,bpf_probe_read可用于读取用户态内存,后续内核版本新增的bpf_probe_read_user在5.4中不可用。
  • Per-CPU数组的每个元素在不同CPU上是独立的,无需考虑并发竞争,适合临时存储tracepoint的上下文数据。
  • 如果需要将数据导出到用户态,建议搭配BPF_MAP_TYPE_PERF_EVENT_ARRAY使用,将Per-CPU数组中的数据拷贝到Perf缓冲区后发送。

内容的提问来源于stack exchange,提问作者dcy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 02:55:14