1

I'm rewrting my code for tc program to csgroup_sbb/xxx and I've noticed direct access to skb data is not possible here (skb-data), so bpf_skb_load_bytes[_relative] is the only way(?) to get skb data.

It worked until I reached the wall.

Verifier at this code:

valp = bpf_ringbuf_reserve(&packets, sizeof(struct packet), ringbuffer_flags);
if (!valp) {
  return 1;
}
void *pto = valp->data;
const __u32 dns_packet_len = skb->len;
if (dns_packet_len > 0 && dns_packet_len < ETH_FRAME_LEN) {
  ok = bpf_skb_load_bytes(skb, 0, pto, dns_packet_len); 
  //...
}

yields this:

; valp = bpf_ringbuf_reserve(&packets, sizeof(struct packet), ringbuffer_flags);
234: (18) r1 = 0xffffc0df80407000     ; R1_w=map_value(off=0,ks=4,vs=8,imm=0)
236: (79) r3 = *(u64 *)(r1 +0)        ; R1_w=map_value(off=0,ks=4,vs=8,imm=0) R3_w=scalar()
; valp = bpf_ringbuf_reserve(&packets, sizeof(struct packet), ringbuffer_flags);
237: (18) r1 = 0xffff9c54905d9400     ; R1_w=map_ptr(off=0,ks=0,vs=0,imm=0)
239: (b7) r2 = 1520                   ; R2_w=1520
240: (85) call bpf_ringbuf_reserve#131        ; R0=ringbuf_mem_or_null(id=11,ref_obj_id=11,off=0,imm=0) refs=11
241: (bf) r8 = r0                     ; R0=ringbuf_mem_or_null(id=11,ref_obj_id=11,off=0,imm=0) R8_w=ringbuf_mem_or_null(id=11,ref_obj_id=11,off=0,imm=0) refs=11
; if (!valp) {
242: (15) if r8 == 0x0 goto pc-211    ; R8_w=ringbuf_mem(ref_obj_id=11,off=0,imm=0) refs=11
; const __u32 dns_packet_len = skb->len;
243: (61) r9 = *(u32 *)(r6 +0)        ; R6=ctx(off=0,imm=0) R9_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) refs=11
; if (dns_packet_len > 0 && dns_packet_len < ETH_FRAME_LEN) {
244: (bf) r1 = r9                     ; R1_w=scalar(id=12,umax=4294967295,var_off=(0x0; 0xffffffff)) R9_w=scalar(id=12,umax=4294967295,var_off=(0x0; 0xffffffff)) refs=11
245: (07) r1 += -1                    ; R1_w=scalar(smin=-1,smax=4294967294) refs=11
246: (67) r1 <<= 32                   ; R1_w=scalar(smax=9223372032559808512,umax=18446744069414584320,var_off=(0x0; 0xffffffff00000000),s32_min=0,s32_max=0,u32_max=0) refs=11
247: (77) r1 >>= 32                   ; R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) refs=11
248: (25) if r1 > 0x5e8 goto pc+23    ; R1_w=scalar(umax=1512,var_off=(0x0; 0x7ff)) refs=11
;
249: (bf) r2 = r8                     ; R2_w=ringbuf_mem(ref_obj_id=11,off=0,imm=0) R8_w=ringbuf_mem(ref_obj_id=11,off=0,imm=0) refs=11
250: (07) r2 += 4                     ; R2_w=ringbuf_mem(ref_obj_id=11,off=4,imm=0) refs=11
; ok = bpf_skb_load_bytes(skb, offset, pto, dns_packet_len); //ok
251: (bf) r1 = r6                     ; R1_w=ctx(off=0,imm=0) R6=ctx(off=0,imm=0) refs=11
252: (bf) r6 = r2                     ; R2_w=ringbuf_mem(ref_obj_id=11,off=4,imm=0) R6_w=ringbuf_mem(ref_obj_id=11,off=4,imm=0) refs=11
253: (bf) r2 = r7                     ; R2_w=28 R7=28 refs=11
254: (bf) r3 = r6                     ; R3_w=ringbuf_mem(ref_obj_id=11,off=4,imm=0) R6_w=ringbuf_mem(ref_obj_id=11,off=4,imm=0) refs=11
255: (bf) r4 = r9                     ; R4_w=scalar(id=12,umax=4294967295,var_off=(0x0; 0xffffffff)) R9_w=scalar(id=12,umax=4294967295,var_off=(0x0; 0xffffffff)) refs=11
256: (85) call bpf_skb_load_bytes#26
invalid access to memory, mem_size=1520 off=4 size=0
R3 min value is outside of the allowed memory range

If I understand it correctly verifier(1) checks lower bounds for len (R4) and it could be 0 (size=0), so this error happens, but on the other hand I've put an additional check if-then condition and it seems to be not enough. I guess it should be a common issue for arrays loading, so if yes how can it be resolve?

additional info:

kernel: 6.2

linux/kernel/bpf/verifier.c

the same error subject but a different context

Maciek Leks
  • 1,288
  • 11
  • 21

1 Answers1

0

Ultimately, a workaround is to compare to 1 not to 0 and set the len variable to 1.

if (dns_packet_len > ETH_FRAME_LEN) {
  dns_packet_len = ETH_FRAME_LEN;
}
if (dns_packet_len < 1) { //verifier will not accept dns_packet_len==0
  //return 1; //verifier won't accept it
  dns_packet_len = 1; //verifier likes it 
}
err = bpf_skb_load_bytes_relative(skb, 0, pto, dns_packet_len, BPF_HDR_START_MAC);  
Maciek Leks
  • 1,288
  • 11
  • 21