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]/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.