iovisor / iovisor/bcc

invalid access to map value, R3 min value is outside of the allowed memory range

Open
#3,269 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C
Stars
22.7k
Forks
4.1k
Avg merge
5d 13h
Merged PRs (30d)
3

Description

Hello,

I am getting verifier failure despite of using suggested workarounds to make verifier happy. Here is the fragment of the code triggering verifier failure:

#define MAX_PACKET_LENGTH 1024

  // Use per CPU array map to be able to store 1k data buffer
   __u32 packet_data_map_id = 0;
    void *packet_data_buffer = NULL;
    packet_data_buffer = bpf_map_lookup_elem(&packet_data_map, &packet_data_map_id);
    if (!packet_data_buffer)
    {
        return;
    }
 // Calculate actual length of  L4+data portion 
   __u32 data_length = (__u32)(data_end - (data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr)));
    // To make verifier happy Start block
    data_length &= 1023;
    int tmp = MAX_PACKET_LENGTH - data_length;
    if (tmp < 0)
    {
        return;
    }
    if (data_length <= 0)
    {
        return;
    }
    // To make verifier happy End block
    ret = bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct ipv6hdr), (void *)&packet_data_buffer[0], data_length);
    if (ret < 0)
    {
        return;
    }

Verifier error:

; ret = bpf_skb_load_bytes(skb, 0, &eth_copy, sizeof(eth_copy));
174: (bf) r1 = r6
175: (b4) w2 = 0
176: (b4) w4 = 14
177: (85) call bpf_skb_load_bytes#26
last_idx 177 first_idx 171
regs=10 stack=0 before 176: (b4) w4 = 14
; if (ret < 0)
178: (c6) if w0 s< 0x0 goto pc+56
 R0_w=inv(id=0,smax_value=9223372034707292159,umax_value=18446744071562067967,var_off=(0x0; 0xffffffff7fffffff),s32_min_value=0,u32_max_value=2147483647) R6=ctx(id=0,off=0,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8=map_value(id=0,off=0,ks=19,vs=256,imm=0) R9=pkt(id=0,off=54,r=54,imm=0) R10=fp0 fp-144=?????mmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-176=???????m fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200=????mmmm
; __u32 packet_data_map_id = 0;
179: (b4) w1 = 0
180: (63) *(u32 *)(r10 -4) = r1
last_idx 180 first_idx 171
regs=2 stack=0 before 179: (b4) w1 = 0
181: (bf) r2 = r10
; 
182: (07) r2 += -4
; packet_data_buffer = bpf_map_lookup_elem(&packet_data_map, &packet_data_map_id);
183: (18) r1 = 0xffff9c5bf6bc4a00
185: (85) call bpf_map_lookup_elem#1
186: (7b) *(u64 *)(r10 -200) = r0
; if (!packet_data_buffer)
187: (15) if r0 == 0x0 goto pc+47
 R0=map_value(id=0,off=0,ks=4,vs=1024,imm=0) R6=ctx(id=0,off=0,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8=map_value(id=0,off=0,ks=19,vs=256,imm=0) R9=pkt(id=0,off=54,r=54,imm=0) R10=fp0 fp-8=mmmm???? fp-144=?????mmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-176=???????m fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200_w=map_value
; __u32 data_length = (__u32)(data_end - (data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr)));
!
188: (1c) w7 -= w9               < ----  data_length is treated as a pointer
!
; data_length &= 1023;
189: (54) w7 &= 1023
; ret = bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct ipv6hdr), packet_data_buffer, data_length);
190: (bf) r1 = r6
191: (b4) w2 = 54
192: (79) r3 = *(u64 *)(r10 -200)
!
193: (bc) w4 = w7    < --- If I read it right then it should contain the u32 data length
!
194: (85) call bpf_skb_load_bytes#26
 R0=map_value(id=0,off=0,ks=4,vs=1024,imm=0) R1_w=ctx(id=0,off=0,imm=0) R2_w=inv54 R3_w=map_value(id=0,off=0,ks=4,vs=1024,imm=0) R4_w=inv(id=0,umax_value=1023,var_off=(0x0; 0x3ff)) R6=ctx(id=0,off=0,imm=0) R7_w=inv(id=0,umax_value=1023,var_off=(0x0; 0x3ff)) R8=map_value(id=0,off=0,ks=19,vs=256,imm=0) R9=pkt(id=0,off=54,r=54,imm=0) R10=fp0 fp-8=mmmm???? fp-144=?????mmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-176=???????m fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200_w=map_value
invalid access to map value, value_size=1024 off=0 size=0
R3 min value is outside of the allowed memory range
processed 183 insns (limit 1000000) max_states_per_insn 0 total_states 12 peak_states 12 mark_read 10

When I use a constant instead of a data_length variable verifier passes:

; packet_data_buffer = bpf_map_lookup_elem(&packet_data_map, &packet_data_map_id);
183: (18) r1 = 0xffff9c59c3a34800
185: (85) call bpf_map_lookup_elem#1
186: (7b) *(u64 *)(r10 -200) = r0
; if (!packet_data_buffer)
187: (15) if r0 == 0x0 goto pc+50
 R0=map_value(id=0,off=0,ks=4,vs=1024,imm=0) R6=ctx(id=0,off=0,imm=0) R7=pkt(id=0,off=54,r=54,imm=0) R8=map_value(id=0,off=0,ks=19,vs=256,imm=0) R9=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm???? fp-144=?????mmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-176=???????m fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200_w=map_value
; ret = bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct ipv6hdr), packet_data_buffer, dl);
188: (bf) r1 = r6
189: (b4) w2 = 54
190: (79) r3 = *(u64 *)(r10 -200)
191: (b4) w4 = 64                                      < ----- parameter passed as length
192: (85) call bpf_skb_load_bytes#26
 R0=map_value(id=0,off=0,ks=4,vs=1024,imm=0) R1_w=ctx(id=0,off=0,imm=0) R2_w=inv54 R3_w=map_value(id=0,off=0,ks=4,vs=1024,imm=0) R4_w=inv64 R6=ctx(id=0,off=0,imm=0) R7=pkt(id=0,off=54,r=54,imm=0) R8=map_value(id=0,off=0,ks=19,vs=256,imm=0) R9=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm???? fp-144=?????mmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-176=???????m fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200_w=map_value
last_idx 192 first_idx 186
regs=10 stack=0 before 191: (b4) w4 = 64
; if (ret < 0)
193: (c6) if w0 s< 0x0 goto pc+44

In both working and non working cases R3 looks exactly the same: R3_w=map_value(id=0,off=0,ks=4,vs=1024,imm=0) the difference is how length parameter is viewed:

  • non working case R4_w get value from R7=invP(id=0,umax_value=1023,var_off=(0x0; 0x3ff)) which make sense and
  • working case R4_w=inv64

I would appreciate if somebody could suggest what else can be done to make verifier happy.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the verifier log around the bpf_map_lookup_elem and bpf_skb_load_bytes calls, comparing the variable-length and constant-length cases shown in the issue. No source file or test is identified, and done would require determining whether BCC or the underlying verifier needs a change and demonstrating the corrected verifier behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
networking, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.