Re: Is it possible to read from a dynamic offset in a packet?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Networking Development]     [Fedora Linux Users]     [Linux SCTP]     [DCCP]     [Gimp]     [Yosemite Campsites]

  Powered by Linux