Hi, I am writing a sample XDP program to parse tcp packet options, code below, compiled ok, when I attach it to a network interface #clang -O2 -emit-llvm -c tcp_option.c -o - |llc -march=bpf -filetype=obj -o tcp_option.o # ip link set dev enp3s0 xdpgeneric object tcp_option.o verbose Prog section 'prog' rejected: Permission denied (13)! - Type: 6 - Instructions: 42 (0 over limit) - License: GPL Verifier analysis: 0: (61) r2 = *(u32 *)(r1 +4) 1: (61) r1 = *(u32 *)(r1 +0) 2: (bf) r3 = r1 3: (07) r3 += 54 4: (b7) r0 = 2 5: (2d) if r3 > r2 goto pc+35 R0_w=inv2 R1_w=pkt(id=0,off=0,r=54,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) R3_w=pkt(id=0,off=54,r=54,imm=0) R10=fp0 6: (71) r2 = *(u8 *)(r1 +12) 7: (71) r3 = *(u8 *)(r1 +13) 8: (67) r3 <<= 8 9: (4f) r3 |= r2 10: (b7) r0 = 2 11: (55) if r3 != 0x8 goto pc+29 R0_w=inv2 R1_w=pkt(id=0,off=0,r=54,imm=0) R2_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R3_w=inv8 R10=fp0 12: (71) r2 = *(u8 *)(r1 +23) 13: (b7) r0 = 2 14: (55) if r2 != 0x6 goto pc+26 R0=inv2 R1=pkt(id=0,off=0,r=54,imm=0) R2=inv6 R3=inv8 R10=fp0 15: (69) r1 = *(u16 *)(r1 +46) 16: (bf) r2 = r1 17: (57) r2 &= 7936 18: (b7) r0 = 2 19: (55) if r2 != 0x200 goto pc+21 R0_w=inv2 R1_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R2_w=inv512 R3=inv8 R10=fp0 20: (77) r1 >>= 2 21: (57) r1 &= 60 22: (07) r1 += -20 23: (18) r2 = 0x0 25: (63) *(u32 *)(r2 +0) = r1 R2 invalid mem access 'inv' <---------------- processed 25 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 1 it appears optlen = tcphdr->doff*4 - sizeof(*tcphdr); is invalid ? if I comment out lines between 60 and 73, no problem with invalid mem access 1 #include <stdint.h> 2 #include <arpa/inet.h> 3 #include <asm/byteorder.h> 4 #include <linux/bpf.h> 5 #include <linux/if_ether.h> 6 #include <linux/ip.h> 7 #include <linux/tcp.h> 8 #include <linux/pkt_cls.h> 9 10 /* 11 * Sample XDP to parse tcp option. 12 * compile it with: 13 * clang -O2 -emit-llvm -c tcp_option.c -o - |llc -march=bpf -filetype=obj -o tcp_option.o 14 * attach it to a device with XDP as: 15 * ip link set dev lo xdp object tcp_option.o verbose 16 */ 17 18 #define SEC(NAME) __attribute__((section(NAME), used)) 19 20 #define TCPOPT_EOL 0 /* End of options (1) */ 21 #define TCPOPT_NOP 1 /* No-op (1) */ 22 #define TCPOPT_MAXSEG 2 /* Maximum segment size (4) */ 23 #define TCPOPT_WSCALE 3 /* Window scaling (3) */ 24 #define TCPOPT_SACKOK 4 /* Selective ACK permitted (2) */ 25 #define TCPOPT_SACK 5 /* Actual selective ACK (10-34) */ 26 #define TCPOPT_TSTAMP 8 /* Timestamp (10) */ 27 28 29 /* from bpf_helpers.h */ 30 31 static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 32 (void *) BPF_FUNC_trace_printk; 33 34 static unsigned long long (*bpf_get_prandom_u32)(void) = 35 (void *) BPF_FUNC_get_prandom_u32; 36 37 const __u8 *op; 38 int i, optlen; 39 40 static int tcp_option(void *data, void *data_end) 41 { 42 struct ethhdr *eth = (struct ethhdr *)data; 43 struct iphdr *iph = (struct iphdr *)(eth + 1); 44 struct tcphdr *tcphdr = (struct tcphdr *)(iph + 1); 45 int tcplen; 46 47 /* sanity check needed by the eBPF verifier */ 48 if ((void *)(tcphdr + 1) > data_end) 49 return 0; 50 51 /* skip non TCP packets */ 52 if (eth->h_proto != __constant_htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP) 53 return 0; 54 55 /* incompatible flags, or PSH already set */ 56 if (tcphdr->ack || tcphdr->fin || tcphdr->rst || tcphdr->psh) 57 return 0; 58 59 if (tcphdr->syn) { 60 optlen = tcphdr->doff*4 - sizeof(*tcphdr); 61 if (!optlen) 62 return -1; 63 /* 64 for (i = 0; i < optlen; ) { 65 if (op[i] == TCPOPT_EOL) { 66 char fmt[] = "XDP: tcp opt eol kind seen %d \n"; 67 bpf_trace_printk(fmt, sizeof(fmt), op[i]); 68 } 69 if (op[i] < 2) 70 i++; 71 else 72 i += op[i+1] ? : 1; 73 } 74 */ 75 76 char fmt[] = "XDP: tcp syn seen \n"; 77 bpf_trace_printk(fmt, sizeof(fmt)); 78 79 } 80 81 return 0; 82 } 83 84 SEC("prog") 85 int xdp_main(struct xdp_md *ctx) 86 { 87 void *data_end = (void *)(uintptr_t)ctx->data_end; 88 void *data = (void *)(uintptr_t)ctx->data; 89 90 if (tcp_option(data, data_end)) 91 return XDP_DROP; 92 93 return XDP_PASS; 94 } 95 96 97 char _license[] SEC("license") = "GPL";