From 58e39f8d58b141b96c030008a20dde9d625ec997 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 1 Nov 2026 19:05:24 +0000 Subject: [PATCH] bpf: Reject non-IPv6 packets in BPF_LWT_ENCAP_SEG6 The mode BPF_LWT_ENCAP_SEG6 of bpf_lwt_push_encap() pushes an IPv6 header and an SRH, and it replaces the dst. The SRH says that IPv6 follows, and skb->protocol does not change. Thus the mode assumes an IPv6 packet, but an lwt_in prog also runs for IPv4 packets. After the prog, bpf_input() calls orig_input() of the old dst. This IPv4 handler reads the pushed headers as IPv4. It can write after the packet data, and the kernel crashes. after the push orig_input() expects --------------------- -------------------- skb->protocol ETH_P_IP ETH_P_IP dst rt6_info rtable packet | IPv6 | SRH | IPv4 | | IPv4 | The mode BPF_LWT_ENCAP_SEG6_INLINE returns -EBADMSG for non-IPv6 packets. Apply this check to both modes. End.BPF does not change, because seg6_local_input() drops non-IPv6 packets. Fixes: fe94cc290f53 ("bpf: Add IPv6 Segment Routing helpers") Signed-off-by: Chris Mason Signed-off-by: Alexei Starovoitov Link: https://patch.msgid.link/20261101190535.1454146-17-alexei.starovoitov@gmail.com --- net/core/filter.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index c0fc9ff04bd5..a69f6817e273 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6927,11 +6927,15 @@ static int bpf_push_seg6_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len if (!seg6_validate_srh(srh, len, false)) return -EINVAL; + /* + * The encap mode names IPv6 as the inner protocol, and neither mode + * updates skb->protocol. + */ + if (skb->protocol != htons(ETH_P_IPV6)) + return -EBADMSG; + switch (type) { case BPF_LWT_ENCAP_SEG6_INLINE: - if (skb->protocol != htons(ETH_P_IPV6)) - return -EBADMSG; - err = seg6_do_srh_inline(skb, srh); break; case BPF_LWT_ENCAP_SEG6: