forked from mirrors/linux
		
	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:8cb3bf8bff("ipv6: ioam: Add support for the ip6ip6 encapsulation") Fixes:6c8702c60b("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") Fixes:a7a29f9c36("net: ipv6: add rpl sr tunnel") Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20250130031519.2716843-2-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									c71a192976
								
							
						
					
					
						commit
						92191dd107
					
				
					 3 changed files with 18 additions and 9 deletions
				
			
		|  | @ -410,9 +410,12 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) | ||||||
| 			goto drop; | 			goto drop; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		local_bh_disable(); | 		/* cache only if we don't create a dst reference loop */ | ||||||
| 		dst_cache_set_ip6(&ilwt->cache, cache_dst, &fl6.saddr); | 		if (dst->lwtstate != cache_dst->lwtstate) { | ||||||
| 		local_bh_enable(); | 			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)); | 		err = skb_cow_head(skb, LL_RESERVED_SPACE(cache_dst->dev)); | ||||||
| 		if (unlikely(err)) | 		if (unlikely(err)) | ||||||
|  |  | ||||||
|  | @ -235,9 +235,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb) | ||||||
| 			goto drop; | 			goto drop; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		local_bh_disable(); | 		/* cache only if we don't create a dst reference loop */ | ||||||
| 		dst_cache_set_ip6(&rlwt->cache, dst, &fl6.saddr); | 		if (orig_dst->lwtstate != dst->lwtstate) { | ||||||
| 		local_bh_enable(); | 			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)); | 		err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); | ||||||
| 		if (unlikely(err)) | 		if (unlikely(err)) | ||||||
|  |  | ||||||
|  | @ -576,9 +576,12 @@ static int seg6_output_core(struct net *net, struct sock *sk, | ||||||
| 			goto drop; | 			goto drop; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		local_bh_disable(); | 		/* cache only if we don't create a dst reference loop */ | ||||||
| 		dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr); | 		if (orig_dst->lwtstate != dst->lwtstate) { | ||||||
| 		local_bh_enable(); | 			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)); | 		err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); | ||||||
| 		if (unlikely(err)) | 		if (unlikely(err)) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jakub Kicinski
						Jakub Kicinski