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

如何修复BPF验证器针对参数的“无界内存访问”错误?

BPF验证器报“R2无界内存访问”问题分析与解决

问题概述

调用bpf_dynptr_from_mem时,已通过if (total_size >= MAX_DATA_SIZE)对传入的total_size参数做边界检查,但BPF验证器仍抛出**“R2无界内存访问”**错误。尝试将total_size的类型从__u32改为__u64后问题依旧;取消注释total_size &= (MAX_DATA_SIZE - 1);语句后,程序可正常通过验证。使用的libbpf版本为libbpf-dev/noble,now 1:1.3.0-2build2 amd64。

相关代码片段

__u32 total_size = insn_len + orig_data->sig_len;
// total_size &= (MAX_DATA_SIZE - 1);
if (total_size >= MAX_DATA_SIZE) {
    bpf_printk("Insufficient buffer size\n");
    ret = -E2BIG;
    goto out;
}

bpf_dynptr_from_mem(combined_buf->data, total_size, 0, &combined_data_ptr);

验证器日志

当total_size为__u32时

; __u32 total_size = insn_len + orig_data->sig_len;
123: (0f) r2 += r9                    ; R2_w=scalar(smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff)) R9=scalar(id=6,smin=smin32=0,smax=umax=smax32=umax32=0xffff8,var_off=(0x0; 0xffff8))
124: (bf) r1 = r2                     ; R1_w=scalar(id=9,smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff)) R2_w=scalar(id=9,smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff))
125: (67) r1 <<= 32                   ; R1_w=scalar(smax=0x7fffffff00000000,umax=0xffffffff00000000,smin32=0,smax32=umax32=0,var_off=(0x0; 0xffffffff00000000))
126: (77) r1 >>= 32                   ; R1_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
127: (b7) r3 = 1048576                ; R3=0x100000
; if (total_size >= MAX_DATA_SIZE) {
128: (2d) if r3 > r1 goto pc+3 132: R0=scalar(id=8) R1=scalar(smin=smin32=0,smax=umax=smax32=umax32=0xfffff,var_off=(0x0; 0xfffff)) R2=scalar(id=9,smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff)) R3=0x100000 R6=map_value(map=modified_signat,ks=4,vs=4100) R7=map_value(map=combined_data_m,ks=4,vs=1052672) R8=map_value(map=original_progra,ks=4,vs=1052680,off=0x101004) R9=scalar(id=6,smin=smin32=0,smax=umax=smax32=umax32=0xffff8,var_off=(0x0; 0xffff8)) R10=fp0 fp-32=dynptr_local(id=4,dynptr_id=1) fp-48=dynptr_local(id=5,dynptr_id=1) fp-72=mmmmmmmm fp-88=map_value(map=combined_data_m,ks=4,vs=1052672) fp-96=map_value(map=original_progra,ks=4,vs=1052680,off=0x101004) fp-104=map_value(map=original_progra,ks=4,vs=1052680,off=0x100004)
; bpf_printk("Insufficient buffer size\n");
132: (b7) r8 = 0                      ; R8_w=0
133: (bf) r4 = r10                    ; R4_w=fp0 R10=fp0
; bpf_dynptr_from_mem(combined_buf->data, total_size, 0, &combined_data_ptr);
134: (07) r4 += -64                   ; R4_w=fp-64
135: (bf) r1 = r7                     ; R1_w=map_value(map=combined_data_m,ks=4,vs=1052672) R7=map_value(map=combined_data_m,ks=4,vs=1052672)
136: (b7) r3 = 0                      ; R3_w=0
137: (85) call bpf_dynptr_from_mem#197
R2 unbounded memory access, use 'var &= const' or 'if (var < const)'

当total_size改为__u64时

; __u64 total_size = insn_len + orig_data->sig_len;
123: (0f) r2 += r9                    ; R2_w=scalar(smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff)) R9=scalar(id=6,smin=smin32=0,smax=umax=smax32=umax32=0xffff8,var_off=(0x0; 0xffff8))
124: (bf) r1 = r2                     ; R1_w=scalar(id=9,smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff)) R2_w=scalar(id=9,smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff))
125: (67) r1 <<= 32                   ; R1_w=scalar(smax=0x7fffffff00000000,umax=0xffffffff00000000,smin32=0,smax32=umax32=0,var_off=(0x0; 0xffffffff00000000))
126: (77) r1 >>= 32                   ; R1_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
127: (b7) r3 = 1048576                ; R3=0x100000
; if (total_size >= MAX_DATA_SIZE) {
128: (2d) if r3 > r1 goto pc+3 132: R0=scalar(id=8) R1=scalar(smin=smin32=0,smax=umax=smax32=umax32=0xfffff,var_off=(0x0; 0xfffff)) R2=scalar(id=9,smin=0,smax=umax=0x1000ffff7,var_off=(0x0; 0x1ffffffff)) R3=0x100000 R6=map_value(map=modified_signat,ks=4,vs=4100) R7=map_value(map=combined_data_m,ks=4,vs=1052672) R8=map_value(map=original_progra,ks=4,vs=1052680,off=0x101004) R9=scalar(id=6,smin=smin32=0,smax=umax=smax32=umax32=0xffff8,var_off=(0x0; 0xffff8)) R10=fp0 fp-32=dynptr_local(id=4,dynptr_id=1) fp-48=dynptr_local(id=5,dynptr_id=1) fp-72=mmmmmmmm fp-88=map_value(map=combined_data_m,ks=4,vs=1052672) fp-96=map_value(map=original_progra,ks=4,vs=1052680,off=0x101004) fp-104=map_value(map=original_progra,ks=4,vs=1052680,off=0x100004)
; bpf_printk("Insufficient buffer size\n");
132: (b7) r8 = 0                      ; R8_w=0
133: (bf) r4 = r10                    ; R4_w=fp0 R10=fp0
; bpf_dynptr_from_mem(combined_buf->data, total_size, 0, &combined_data_ptr);
134: (07) r4 += -64                   ; R4_w=fp-64
135: (bf) r1 = r7                     ; R1_w=map_value(map=combined_data_m,ks=4,vs=1052672) R7=map_value(map=combined_data_m,ks=4,vs=1052672)
136: (b7) r3 = 0                      ; R3_w=0
137: (85) call bpf_dynptr_from_mem#197
R2 unbounded memory access, use 'var &= const' or 'if (var < const)'

原因分析

BPF验证器的数据流分析对条件判断的识别存在局限性:

  • if (total_size >= MAX_DATA_SIZE)的分支逻辑虽在语义上保证后续total_size不会超过阈值,但验证器未能正确推导该约束,仍认为total_size的上限未明确限制。
  • total_size &= (MAX_DATA_SIZE - 1);是位运算强制边界,直接将total_size的值限制在0到MAX_DATA_SIZE-1范围内,验证器可明确识别这个硬约束,因此不再报错。

解决方法

有两种可行方案:

  1. 保留位运算语句:total_size &= (MAX_DATA_SIZE - 1);,直接强制限制total_size范围(仅适用于MAX_DATA_SIZE是2的幂的情况)。
  2. 调整条件判断为验证器推荐形式:将if (total_size >= MAX_DATA_SIZE)改为if (total_size > MAX_DATA_SIZE - 1)或if (total_size < MAX_DATA_SIZE),让验证器能正确识别边界约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:54:51