diff --git a/Tethering/bpf_progs/bpf_tethering.h b/Tethering/bpf_progs/bpf_tethering.h index 10e6bb0a6f..4e006db117 100644 --- a/Tethering/bpf_progs/bpf_tethering.h +++ b/Tethering/bpf_progs/bpf_tethering.h @@ -41,6 +41,7 @@ ERR(CHECKSUM) \ ERR(NON_TCP_UDP) \ ERR(NON_TCP) \ + ERR(SHORT_L4_HEADER) \ ERR(SHORT_TCP_HEADER) \ ERR(SHORT_UDP_HEADER) \ ERR(TRUNCATED_IPV4) \ diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c index d4b5246a71..30b1f491f8 100644 --- a/Tethering/bpf_progs/offload.c +++ b/Tethering/bpf_progs/offload.c @@ -403,6 +403,18 @@ static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool // out all the non-tcp logic. Also note that at this point is_udp === !is_tcp. const bool is_tcp = !updatetime || (ip->protocol == IPPROTO_TCP); + // This is a bit of a hack to make things easier on the bpf verifier. + // (In particular I believe the Linux 4.14 kernel's verifier can get confused later on about + // what offsets into the packet are valid and can spuriously reject the program, this is + // because it fails to realize that is_tcp && !is_tcp is impossible) + // + // For both TCP & UDP we'll need to read and modify the src/dst ports, which so happen to + // always be in the first 4 bytes of the L4 header. Additionally for UDP we'll need access + // to the checksum field which is in bytes 7 and 8. While for TCP we'll need to read the + // TCP flags (at offset 13) and access to the checksum field (2 bytes at offset 16). + // As such we *always* need access to at least 8 bytes. + if (data + l2_header_size + sizeof(*ip) + 8 > data_end) PUNT(SHORT_L4_HEADER); + struct tcphdr* tcph = is_tcp ? (void*)(ip + 1) : NULL; struct udphdr* udph = is_tcp ? NULL : (void*)(ip + 1);