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

已做边界检查仍触发eBPF map值非法访问问题排查

eBPF数组Map越界访问问题排查与解决建议

尝试通过索引和偏移量从array类型的eBPF map读取字节,已执行边界检查,但仍触发invalid access to map value错误,怀疑与溢出风险有关。

相关代码

struct bpf_elf_map __section("maps") data_store = {
    .type = BPF_MAP_TYPE_ARRAY,
    .size_key = sizeof(__u32),
    .size_value = 1024,
    .max_elem = 4096,
    .pinning = PIN_GLOBAL_NS,
};

static __always_inline void read_data(__u32 idx, __u32 offset, void *dst,
                                      __u32 size) {
  if (size > 512 || offset >= 1024) {
    // for the ebpf verifier
    return;
  }
  void *b = bpf_map_lookup_elem(&data_store, &idx);
  if (!b) {
    // shouldn't happen
    return;
  }

  if (offset + size <= 1024) {
    for (__u32 i = 0; i < size && i < 512; ++i) {
      if (offset + i >= 1024) {
        return;
      }
      // !! where the verifier complains
      memcpy(dst + i, b + offset + i, sizeof(__u8));
    }
  } else {
    // ...
  }
}

验证器日志

; for (__u32 i = 0; i < size && i < 512; ++i) {
197: (25) if r1 > 0x1fe goto pc+8
;
198: (bf) r2 = r1
199: (07) r2 += 1
; for (__u32 i = 0; i < size && i < 512; ++i) {
200: (3d) if r2 >= r8 goto pc+5
 R0=map_value(id=0,off=0,ks=4,vs=1024,umax_value=1023,var_off=(0x0; 0x3ff)) R1=invP0 R2_w=invP1 R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=map_value(id=0,off=0,ks=4,vs=32,imm=0) R7=map_value(id=0,off=0,ks=4,vs=512,imm=0) R8=inv(id=261,umin_value=2,umax_value=512,var_off=(0x0; 0x3ff)) R9=invP(id=0,umin_value=1,umax_value=1024,var_off=(0x0; 0x7ff)) R10=fp0 fp-8=mmmmm??? fp-48=????mmmm
201: (bf) r3 = r9
202: (0f) r3 += r1
203: (bf) r1 = r2
204: (25) if r3 > 0x3ff goto pc+1
 R0=map_value(id=0,off=0,ks=4,vs=1024,umax_value=1023,var_off=(0x0; 0x3ff)) R1=invP1 R2=invP1 R3=invP(id=0,umin_value=1,umax_value=1023,var_off=(0x0; 0x3ff)) R6=map_value(id=0,off=0,ks=4,vs=32,imm=0) R7=map_value(id=0,off=0,ks=4,vs=512,imm=0) R8=inv(id=261,umin_value=2,umax_value=512,var_off=(0x0; 0x3ff)) R9=invP(id=263,umin_value=1,umax_value=1024,var_off=(0x0; 0x7ff)) R10=fp0 fp-8=mmmmm??? fp-48=????mmmm
205: (05) goto pc-15
; memcpy(dst + i, b + offset + i, sizeof(__u8));
191: (bf) r2 = r7
192: (0f) r2 += r1
193: (bf) r3 = r0
194: (0f) r3 += r1
195: (71) r3 = *(u8 *)(r3 +0)
 R0=map_value(id=0,off=0,ks=4,vs=1024,umax_value=1023,var_off=(0x0; 0x3ff)) R1=invP1 R2_w=map_value(id=0,off=1,ks=4,vs=512,imm=0) R3_w=map_value(id=0,off=1,ks=4,vs=1024,umax_value=1023,var_off=(0x0; 0x3ff)) R6=map_value(id=0,off=0,ks=4,vs=32,imm=0) R7=map_value(id=0,off=0,ks=4,vs=512,imm=0) R8=inv(id=261,umin_value=2,umax_value=512,var_off=(0x0; 0x3ff)) R9=invP(id=263,umin_value=1,umax_value=1024,var_off=(0x0; 0x7ff)) R10=fp0 fp-8=mmmmm??? fp-48=????mmmm
invalid access to map value, value_size=1024 off=1024 size=1
R3 max value is outside of the allowed memory range

解决建议

  • 合并简化边界检查:分散的检查逻辑会让eBPF验证器无法准确追踪变量范围。提前一次性完成所有校验,将offset >=1024改为offset >1023(无符号整数等于1024时直接越界),同时确认offset + size <=1024。
  • 移除循环内冗余检查:进入循环前已确认offset + size <=1024,循环内的if (offset + i >=1024)完全多余,反而干扰验证器的数据流分析。
  • 替换单字节memcpy为直接指针访问:单字节memcpy效率低且不利于验证器识别内存范围,改用数组下标或指针赋值更清晰。
  • 优化循环条件:循环条件只需i < size,前面已限制size <=512,无需重复判断i <512。

修改后的示例代码

static __always_inline void read_data(__u32 idx, __u32 offset, void *dst, __u32 size) {
    // 一次性完成所有边界检查,明确告知验证器变量范围
    if (size > 512 || offset > 1023 || (offset + size) > 1024) {
        return;
    }
    void *b = bpf_map_lookup_elem(&data_store, &idx);
    if (!b) {
        return;
    }
    // 转换为字节指针直接拷贝
    __u8 *src_ptr = (__u8 *)b + offset;
    __u8 *dst_ptr = (__u8 *)dst;
    for (__u32 i = 0; i < size; ++i) {
        dst_ptr[i] = src_ptr[i];
    }
}

说明

修改后的代码通过提前明确的边界检查,让eBPF验证器能清晰识别src_ptr + i的访问范围始终在0到1023之间(符合map的value_size=1024约束),简化的逻辑也降低了验证器的分析复杂度,避免误判越界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 04:55:18