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