bpf: Require BPF_LWT_REROUTE when an lwt_in prog changes the protocol

When an lwt_in prog returns BPF_OK, bpf_input() calls orig_input(), the
input handler of the route. This handler is for one IP version and needs a
dst of the same family. But BPF_LWT_ENCAP_IP lets the prog push a header of
the other IP version and thus change skb->protocol. Then the handler reads
and changes a header of the other IP version. The push of an SRH also
replaces the dst, because seg6_lookup_nexthop() puts an rt6_info into the
skb. Then ip_forward() uses the rt6_info as a struct rtable.

Drop the skb with -EINVAL when skb->protocol changes, as bpf_xmit() does.
Drop it also when the family of the dst changes, because skb->protocol does
not always show this change. Today no such skb leaves as the prog made it.
A prog works as before if it returns BPF_LWT_REROUTE, or if it pushes an
SRH on an IPv6 route.

The commit in the first Fixes tag lets a prog change skb->protocol. The
commit in the second tag adds the check to bpf_xmit() only.

Fixes: 52f278774e ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap")
Fixes: 3bd0b15281 ("bpf: add handling of BPF_LWT_REROUTE to lwt_bpf.c")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-24-alexei.starovoitov@gmail.com
This commit is contained in:
Alexei Starovoitov 2026-11-01 19:05:31 +00:00
parent b3ad42f618
commit d9618a6196
No known key found for this signature in database

View File

@ -165,6 +165,16 @@ static int bpf_input(struct sk_buff *skb)
bpf_lwt_reset_cb(skb, proto);
if (ret == BPF_LWT_REROUTE)
return bpf_lwt_input_reroute(skb);
/*
* orig_input() is for the old protocol only, see bpf_xmit().
* It also needs a dst of the old family. BPF_LWT_ENCAP_SEG6
* puts an IPv6 dst into the skb.
*/
if (skb->protocol != proto ||
skb_dst(skb)->ops->family != dst->ops->family) {
kfree_skb(skb);
return -EINVAL;
}
}
if (unlikely(!dst->lwtstate->orig_input)) {