Skip to content

Commit 92191dd

Browse files
committed
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: 8cb3bf8 ("ipv6: ioam: Add support for the ip6ip6 encapsulation") Fixes: 6c8702c ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") Fixes: a7a29f9 ("net: ipv6: add rpl sr tunnel") Reviewed-by: Simon Horman <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent c71a192 commit 92191dd

File tree

3 files changed

+18
-9
lines changed

3 files changed

+18
-9
lines changed

net/ipv6/ioam6_iptunnel.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,12 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
410410
goto drop;
411411
}
412412

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

417420
err = skb_cow_head(skb, LL_RESERVED_SPACE(cache_dst->dev));
418421
if (unlikely(err))

net/ipv6/rpl_iptunnel.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
235235
goto drop;
236236
}
237237

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

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

net/ipv6/seg6_iptunnel.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,12 @@ static int seg6_output_core(struct net *net, struct sock *sk,
576576
goto drop;
577577
}
578578

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

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

0 commit comments

Comments
 (0)