Reputation: 3389
I'm trying to parse the first couple of bytes of a packet passed to a stream_parser
program. However, I'm running into a few problems that make little sense to me. Here's the program:
__u32 len = 256;
// uncommenting this breaks it even using the regular for loop
// if (len > skb->len) len = skb->len;
if (bpf_skb_pull_data(skb, len) < 0) {
return -1;
}
char *data_end = (char *)(long)skb->data_end;
char *data = (char *)(long)skb->data;
if (data + len > data_end) {
return -1;
}
__u32 k = 0;
bpf_for(k, 0, len) {
__u32 i = k & 0xFF;
if (i < len && data + i > data_end) break;
bpf_printk("data[i] = %d", data[i]);
}
// this works!
// for (__u32 i = 0; i < len; i++) {
// if (data + i > data_end) break;
// bpf_printk("data[i] = %d", data[i]);
// }
And here's output of the verifier:
0: R1=ctx() R10=fp0
; int bpf_prog_parser(struct __sk_buff *skb) {
0: (bf) r6 = r1 ; R1=ctx() R6_w=ctx()
; if (bpf_skb_pull_data(skb, len) < 0) {
1: (b7) r2 = 256 ; R2_w=256
2: (85) call bpf_skb_pull_data#39 ; R0_w=scalar()
3: (b7) r1 = 0 ; R1_w=0
; if (bpf_skb_pull_data(skb, len) < 0) {
4: (6d) if r1 s> r0 goto pc+50 ; R0_w=scalar(smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff)) R1_w=0
; char *data_end = (char *)(long)skb->data_end;
5: (61) r8 = *(u32 *)(r6 +80) ; R6_w=ctx() R8_w=pkt_end()
; char *data = (char *)(long)skb->data;
6: (61) r9 = *(u32 *)(r6 +76) ; R6_w=ctx() R9_w=pkt(r=0)
; if (data + len > data_end) {
7: (bf) r1 = r9 ; R1_w=pkt(r=0) R9_w=pkt(r=0)
8: (07) r1 += 256 ; R1=pkt(off=256,r=0)
; if (data + len > data_end) {
9: (2d) if r1 > r8 goto pc+45 ; R1=pkt(off=256,r=256) R8=pkt_end()
10: (bf) r7 = r10 ; R7_w=fp0 R10=fp0
;
11: (07) r7 += -24 ; R7_w=fp-24
; bpf_for(k, 0, len) {
12: (bf) r1 = r7 ; R1_w=fp-24 R7_w=fp-24
13: (b7) r2 = 0 ; R2_w=0
14: (b7) r3 = 256 ; R3_w=256
15: (85) call bpf_iter_num_new#76394 ; R0_w=scalar() fp-24_w=iter_num(ref_id=1,state=active,depth=0) refs=1
; bpf_for(k, 0, len) {
16: (bf) r1 = r7 ; R1=fp-24 R7=fp-24 refs=1
17: (85) call bpf_iter_num_next#76396 18: R0_w=rdonly_mem(id=2,ref_obj_id=1,sz=4) R6=ctx() R7=fp-24 R8=pkt_end() R9=pkt(r=256) R10=fp0 fp-24=iter_num(ref_id=1,state=active,depth=1) refs=1
; bpf_for(k, 0, len) {
18: (15) if r0 == 0x0 goto pc+17 ; R0_w=rdonly_mem(id=2,ref_obj_id=1,sz=4) refs=1
19: (61) r1 = *(u32 *)(r0 +0) ; R0_w=rdonly_mem(id=2,ref_obj_id=1,sz=4) R1_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff)) refs=1
; bpf_for(k, 0, len) {
20: (25) if r1 > 0xff goto pc+15 ; R1_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) refs=1
; if (i < len && data + i > data_end) break;
21: (bf) r2 = r9 ; R2_w=pkt(r=256) R9=pkt(r=256) refs=1
22: (0f) r2 += r1 ; R1=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R2=pkt(id=5,r=0,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) refs=1
; if (i < len && data + i > data_end) break;
23: (2d) if r2 > r8 goto pc+12 ; R2=pkt(id=5,r=0,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R8=pkt_end() refs=1
; bpf_printk("data[i] = %d", data[i]);
24: (71) r3 = *(u8 *)(r2 +0)
invalid access to packet, off=0 size=1, R2(id=5,off=0,r=0)
R2 offset is outside of the packet
processed 55 insns (limit 1000000) max_states_per_insn 0 total_states 5 peak_states 5 mark_read 2
I have three questions:
bpf_loop
not? I would use the regular for loop but this also doesn't work because the number of instructions explodes.len
to skb->len
. Doing so breaks the verification for both loop variants. Why is that? After all, the upper limit of 256 still holds.Essentially, I just want to read the first couple of bytes. I know that the verifier is not perfect but I assume that very basic parsing is possible.
Thanks in advance for any help!
Upvotes: 0
Views: 171