Commit 92191dd1 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

net: ipv6: fix dst ref loops in rpl, seg6 and ioam6 lwtunnels



Some lwtunnels have a dst cache for post-transformation dst.
If the packet destination did not change we may end up recording
a reference to the lwtunnel in its own cache, and the lwtunnel
state will never be freed.

Discovered by the ioam6.sh test, kmemleak was recently fixed
to catch per-cpu memory leaks. I'm not sure if rpl and seg6
can actually hit this, but in principle I don't see why not.

Fixes: 8cb3bf8b ("ipv6: ioam: Add support for the ip6ip6 encapsulation")
Fixes: 6c8702c6 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels")
Fixes: a7a29f9c ("net: ipv6: add rpl sr tunnel")
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250130031519.2716843-2-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent c71a1929
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -410,9 +410,12 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
			goto drop;
		}

		/* cache only if we don't create a dst reference loop */
		if (dst->lwtstate != cache_dst->lwtstate) {
			local_bh_disable();
			dst_cache_set_ip6(&ilwt->cache, cache_dst, &fl6.saddr);
			local_bh_enable();
		}

		err = skb_cow_head(skb, LL_RESERVED_SPACE(cache_dst->dev));
		if (unlikely(err))
+6 −3
Original line number Diff line number Diff line
@@ -235,9 +235,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
			goto drop;
		}

		/* cache only if we don't create a dst reference loop */
		if (orig_dst->lwtstate != dst->lwtstate) {
			local_bh_disable();
			dst_cache_set_ip6(&rlwt->cache, dst, &fl6.saddr);
			local_bh_enable();
		}

		err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
		if (unlikely(err))
+6 −3
Original line number Diff line number Diff line
@@ -576,9 +576,12 @@ static int seg6_output_core(struct net *net, struct sock *sk,
			goto drop;
		}

		/* cache only if we don't create a dst reference loop */
		if (orig_dst->lwtstate != dst->lwtstate) {
			local_bh_disable();
			dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
			local_bh_enable();
		}

		err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
		if (unlikely(err))