From: Josef Bacik bpf_lwt_seg6_action(SEG6_LOCAL_ACTION_END_DT6) pulls the outer headers off the packet and hands it to seg6_lookup_nexthop(), which reads the inner IPv6 header at skb->data. Nothing says that this header is in the head of the skb, or that there is one. If the head ends with the outer headers, the route is looked up for whatever lies behind the head, and the packet is dropped or leaves by the wrong route. If the program then pushes an SRH with SEG6_LOCAL_ACTION_END_B6, seg6_do_srh_inline() pulls an IPv6 header off a head which has none, and __skb_pull() hits its BUG(): the kernel panics on a packet from the network. GRO pulls the inner header of a plain IPv6 in IPv6 packet into the head. It takes a packet which GRO does not look into that far, one with a fragment header in front of the inner header for example, or a device without GRO, and a driver which leaves the inner header in a fragment. Make sure of the inner header together with the outer ones. The program goes on behind an error of the helper, so do it before the packet is changed. A pull which fails can still have moved the head, so look for the SRH again. Fixes: 486cdf21583e ("bpf: add End.DT6 action to bpf_lwt_seg6_action helper") Signed-off-by: Josef Bacik Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 6ac386dea4e8..be792b160e18 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7063,9 +7063,14 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb, if (ipv6_find_hdr(skb, &hdroff, IPPROTO_IPV6, NULL, NULL) < 0) return -EBADMSG; - if (!pskb_pull(skb, hdroff)) + /* As long as nothing has been changed, the program goes on */ + if (!pskb_may_pull(skb, hdroff + sizeof(struct ipv6hdr))) { + /* but the head may have moved */ + bpf_update_srh_state(skb); return -EBADMSG; + } + __skb_pull(skb, hdroff); skb_postpull_rcsum(skb, skb_network_header(skb), hdroff); skb_reset_network_header(skb); skb_reset_transport_header(skb); -- 2.55.0