Thanks very much, that trick worked! --Zvi On Fri, Jun 8, 2018 at 5:44 AM, Daniel Borkmann <daniel@xxxxxxxxxxxxx> wrote: > On 06/07/2018 10:51 PM, Zvi Effron wrote: >> Thank you! That works when I write the opcodes by hand. >> >> When using clang (6.0.0) to compile from C code, however, the register >> allocator does not seem to want to reuse the register it used for the >> comparison for the read, causing a verifier failure. >> Is there a good method for getting clang to reuse the register it used >> for the comparison for the read? >> >> ===== BEGIN CODE ===== >> #include <linux/bpf.h> >> #include <linux/if_ether.h> >> #include <linux/ip.h> >> >> static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = >> (void *)BPF_FUNC_trace_printk; >> >> int xdp_program(struct xdp_md *context) { >> void* frame_end = (void *)(long)context->data_end; >> >> void *frame_start = (void*)(long)context->data; >> if (frame_start + sizeof(struct ethhdr) + sizeof(struct iphdr) > frame_end) { >> return XDP_PASS; >> } >> >> if (__builtin_bswap16(((struct ethhdr*)frame_start)->h_proto) != ETH_P_IP) { >> return XDP_PASS; >> } >> >> __u16 payload_length = __builtin_bswap16(((struct iphdr*)(frame_start >> + sizeof(struct ethhdr)))->tot_len - sizeof(struct iphdr)); >> if (payload_length > 1500) { >> return XDP_PASS; >> } >> >> if (frame_start + sizeof(struct ethhdr) + sizeof(struct iphdr) + >> payload_length > frame_end) { >> return XDP_PASS; >> } >> int last_byte_payload_offset = payload_length - 1; >> __u8 byte = ((__u8*)frame_start + sizeof(struct ethhdr) + >> sizeof(struct iphdr))[last_byte_payload_offset]; >> char fmt[] = "Packet's last byte was 0x%x\n"; >> bpf_trace_printk(fmt, sizeof(fmt), byte); > > Should break here in the last part since verifier is only aware that > access up to frame_start + sizeof(struct ethhdr) + sizeof(struct iphdr) > is safe. So you would need roughly something like this: > > __u8 *ptr = frame_start + sizeof(struct ethhdr) + sizeof(struct iphdr) + > last_byte_payload_offset > if (ptr + 1 > frame_end) > return ...; > bpf_trace_printk(fmt, sizeof(fmt), *ptr); > > Cheers, > Daniel > >> return XDP_TX; >> } >> >> char _license[] __attribute__((section("license"), used)) = "GPL"; >> ===== END CODE ===== >> >> The above code was compiled with clang -O2 -Wall -Werror -target bpf -c -g. >> >> When attempting to install the program, the verifier complained with >> >> ===== BEGIN VERIFIER OUTPUT ===== >> Verifier analysis: >> >> 0: (b7) r0 = 2 >> 1: (61) r2 = *(u32 *)(r1 +4) >> 2: (61) r3 = *(u32 *)(r1 +0) >> 3: (bf) r1 = r3 >> 4: (07) r1 += 34 >> 5: (2d) if r1 > r2 goto pc+32 >> R0=inv2 R1=pkt(id=0,off=34,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) >> R3=pkt(id=0,off=0,r=34,imm=0) R10=fp0,call_-1 >> 6: (71) r4 = *(u8 *)(r3 +12) >> 7: (71) r5 = *(u8 *)(r3 +13) >> 8: (67) r5 <<= 8 >> 9: (4f) r5 |= r4 >> 10: (55) if r5 != 0x8 goto pc+27 >> R0=inv2 R1=pkt(id=0,off=34,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) >> R3=pkt(id=0,off=0,r=34,imm=0) R4=inv(id=0,umax_value=255,var_off=(0x0; >> 0xff)) R5=inv8 R10=fp0,call_-1 >> 11: (69) r3 = *(u16 *)(r3 +16) >> 12: (07) r3 += 65516 >> 13: (dc) r3 = be16 r3 >> 14: (25) if r3 > 0x5dc goto pc+23 >> R0=inv2 R1=pkt(id=0,off=34,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) >> R3=inv(id=0,umax_value=1500,var_off=(0x0; 0x7ff)) >> R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R5=inv8 >> R10=fp0,call_-1 >> 15: (bf) r4 = r1 >> 16: (0f) r4 += r3 >> 17: (2d) if r4 > r2 goto pc+20 >> R0=inv2 R1=pkt(id=0,off=34,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) >> R3=inv(id=0,umax_value=1500,var_off=(0x0; 0x7ff)) >> R4=pkt(id=1,off=34,r=34,umax_value=1500,var_off=(0x0; 0x7ff)) R5=inv8 >> R10=fp0,call_-1 >> 18: (0f) r1 += r3 >> 19: (71) r3 = *(u8 *)(r1 -1) >> invalid access to packet, off=33 size=1, R1(id=2,off=34,r=0) >> R1 offset is outside of the packet >> >> Error fetching program/map! >> ===== END VERIFIER OUTPUT ===== >> >> Thank you! >> --Zvi