The issue: This is a follow-up to the short link-layer header fixes[Link]. After vlan pop_eth, a privileged SCHED_ACT BPF program can call bpf_skb_change_head(skb, 1, 0) and then bpf_redirect_neigh(). __bpf_redirect_neigh() calls skb_pull(skb, sizeof(*ethh)) after checking only that mac_header < network_header. It does not check that the MAC header is long enough or that it is linear. A SCHED_ACT BPF program can do: bpf_skb_change_head(skb, 1, 0); bpf_redirect_neigh(lo, NULL, 0, 0); after vlan pop_eth. The skb then has mac_len == 1 and only one byte of linear data; skb_pull(ETH_HLEN) trips the skb->len < skb->data_len BUG in __skb_pull(): kernel BUG at include/linux/skbuff.h:2839 RIP: skb_pull+0xc5/0x100 Call Trace: skb_do_redirect -> ... The Fix: Drop skbs whose MAC header is shorter than ETH_HLEN, and use pskb_may_pull() to ensure the Ethernet header is linear before reading or pulling it. Re-read ethh after pskb_may_pull(), which may reallocate skb->head. Fixes: b4ab31414970 ("bpf: Add redirect_neigh helper as redirect drop-in") Link: https://lore.kernel.org/netdev/20261027082604.1485903-1-edumazet@kernel.org/ Cc: stable@vger.kernel.org Signed-off-by: Jamal Hadi Salim --- net/core/filter.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 70dc621672f2..4d344ec09736 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2432,10 +2432,14 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev, static int __bpf_redirect_neigh(struct sk_buff *skb, struct net_device *dev, struct bpf_nh_params *nh) { - struct ethhdr *ethh = eth_hdr(skb); + struct ethhdr *ethh; if (unlikely(skb->mac_header >= skb->network_header)) goto out; + if (unlikely(skb->mac_len < ETH_HLEN || + !pskb_may_pull(skb, ETH_HLEN))) + goto out; + ethh = eth_hdr(skb); bpf_push_mac_rcsum(skb); if (is_multicast_ether_addr(ethh->h_dest)) goto out; -- 2.43.0