In bpf_skb_load_helper_convert_offset(), SKF_LL_OFF checks skb_mac_header_was_set(skb), whereas SKF_NET_OFF unconditionally returns: offset - SKF_NET_OFF + skb_network_offset(skb); Unlike skb->mac_header (which __alloc_skb() initializes to ~0U), skb->network_header is zero-initialized to 0. On sockets that reserve headroom via skb_reserve() without setting a network header (such as AF_UNIX sockets), skb->network_header remains 0, so skb_network_offset(skb) evaluates to (skb->head - skb->data) = -headroom. When bpf_skb_load_helper_(8, 16, 32)() then checks: if (headlen - offset >= len) return *(u8 *)(data + offset); a negative converted offset (-headroom) satisfies `headlen - offset >= len` and reads uninitialized skb->head headroom before skb->data (or before skb_mac_header(skb) if mac_header was set without setting network_header). Validate that skb->network_header is >= skb->mac_header when the MAC header is set, or that skb_network_offset(skb) >= 0 and a network protocol/header is present otherwise, returning INT_MIN (-EFAULT) when the network header is unset. Fixes: d4bac0288a2b ("bpf: support SKF_NET_OFF and SKF_LL_OFF on skb frags") Assisted-by: LLM Signed-off-by: Hui Peng --- diff --git a/net/core/filter.c b/net/core/filter.c --- a/net/core/filter.c +++ b/net/core/filter.c @@ -231,8 +231,14 @@ static int bpf_skb_load_helper_convert_offset(const struct sk_buff *skb, int off if (likely(offset >= 0)) return offset; - if (offset >= SKF_NET_OFF) + if (offset >= SKF_NET_OFF) { + if (skb_mac_header_was_set(skb) ? + skb->network_header < skb->mac_header : + (skb_network_offset(skb) < 0 || + (!skb->protocol && !skb->network_header))) + return INT_MIN; return offset - SKF_NET_OFF + skb_network_offset(skb); + } if (offset >= SKF_LL_OFF && skb_mac_header_was_set(skb)) return offset - SKF_LL_OFF + skb_mac_offset(skb); -- 2.43.0