Re: [PATCH net 1/1] seg6: reset IP6CB after IPv6 decapsulation
Andrea Mayer <[email protected]>
| Newsgroups | org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On Mon, 17 Aug 2026 00:09:29 +0800 Zhiling Zou <[email protected]> wrote: Hi Zhiling, thank you for the patch and the reproducer. I reported the same stale IP6CB while reviewing an IPv4 fix for the same helper [1]. Some comments below. > decap_and_validate() pulls the outer SRv6 headers and makes the > inner packet the skb network header. The IPv6 control block still > contains values collected while parsing the outer packet, including > nhoff and extension-header flags. > > End.DX6 and End.DT6 then route the inner IPv6 packet directly to > the IPv6 input path. If an outer extension header left a large > nhoff, ip6_protocol_deliver_rcu() reads > skb_network_header(skb)[nhoff] from the inner packet, which may be > beyond the skb head. A KASAN trace trimmed to the relevant calls from the cover letter would help here, along with the reachability. The commit is what lands in git log. > Clear IP6CB after IPv6 decapsulation, restore the incoming interface, > and initialize nhoff to the inner IPv6 base-header nexthdr field before > delivering the packet. > > Fixes: d7a669dd2f8b ("ipv6: sr: add helper functions for seg6local") > Cc: [email protected] > Reported-by: Vega <[email protected]> > Signed-off-by: Zhiling Zou <[email protected]> > --- > net/ipv6/seg6_local.c | 5 +++++ > 1 file changed, 5 insertions(+) > > diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c > index 2b41e4c0dddd1..4df76fa85d6b4 100644 > --- a/net/ipv6/seg6_local.c > +++ b/net/ipv6/seg6_local.c > @@ -253,6 +253,11 @@ static bool decap_and_validate(struct sk_buff *skb, int proto) > > skb_reset_network_header(skb); > skb_reset_transport_header(skb); > + if (proto == IPPROTO_IPV6) { > + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); > + IP6CB(skb)->iif = skb->skb_iif; > + IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); > + } > if (iptunnel_pull_offloads(skb)) > return false; The index would need to come from IP6CB->iif, saving it before the memset. ip6_rcv_core() sets that field before l3mdev runs, and vrf_ip6_rcv() then replaces skb->skb_iif with the master without touching IP6CB->iif. I measured it on net/main and on two variants of the fix, one taking the index from skb->skb_iif and one from IP6CB->iif. The receiver is a UDP socket bound to the VRF reading IPV6_PKTINFO, the datagram arrives on ifindex 8, and the VRF device is 9: no patch skb->skb_iif IP6CB->iif without decapsulation 8 8 8 End.DT6 vrftable 8 9 8 End.DT6 table 8 9 8 The patch that fixes the IPv4 side uses IP6CB->iif for this reason [2]. IP6SKB_L3SLAVE would also need to be carried across. vrf_ip6_rcv() sets that flag on the outer packet, and the memset drops it. Something like this: bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags); int iif = IP6CB(skb)->iif; memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); IP6CB(skb)->iif = iif; IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); if (l3slave) IP6CB(skb)->flags |= IP6SKB_L3SLAVE; The fix for the IPv4 side of this helper is now at its v4 [2]. Both touch decap_and_validate(), so your block would go next to theirs as an else if. Thanks, Ciao, Andrea [1] https://lore.kernel.org/netdev/[email protected]/ [2] https://lore.kernel.org/netdev/[email protected]/