diff --git a/xdp/xdp_wg_mtu_optimizer.c b/xdp/xdp_wg_mtu_optimizer.c index a47d03f..012944d 100644 --- a/xdp/xdp_wg_mtu_optimizer.c +++ b/xdp/xdp_wg_mtu_optimizer.c @@ -43,6 +43,15 @@ struct { __type(value, __u16); // MTU conhecido } path_mtu_map SEC(".maps"); +// Barreira de compilador: impede o clang de "provar" (via -O2) que um +// ponteiro já está implicitamente dentro de um range válido por +// transitividade com outro ponteiro checado antes, e por isso eliminar do +// bytecode um check de bounds que na prática é redundante *matematicamente* +// mas que o verificador do kernel exige ver explicitamente antes de cada +// dereferência. Gotcha clássico de eBPF — aparece até nos selftests do +// próprio kernel para parsing de opções TCP. +#define barrier_var(var) asm volatile("" : "+r"(var)) + // Atualização incremental de checksum de 16 bits (RFC 1071/1624) — a mesma // técnica usada pelo csum_replace2() do kernel. Necessária porque XDP não // tem acesso a helpers de checksum baseados em skb (bpf_l4_csum_replace só @@ -86,6 +95,7 @@ static __always_inline int clamp_tcp_mss(struct tcphdr *tcp, void *data_end, __u // que por convenção vem logo no início das opções. #pragma unroll for (int i = 0; i < 10; i++) { + barrier_var(opt); if ((void *)(opt + 1) > data_end || opt >= opt_end) break; @@ -97,6 +107,7 @@ static __always_inline int clamp_tcp_mss(struct tcphdr *tcp, void *data_end, __u continue; } + barrier_var(opt); if ((void *)(opt + 2) > data_end || opt + 1 >= opt_end) break; __u8 opt_len = opt[1]; @@ -104,6 +115,7 @@ static __always_inline int clamp_tcp_mss(struct tcphdr *tcp, void *data_end, __u break; if (kind == 2 && opt_len == 4) { // Maximum Segment Size + barrier_var(opt); if ((void *)(opt + 4) > data_end) break; __be16 *mss_ptr = (__be16 *)(opt + 2);