forked from mirrors/linux
		
	net: ipv6: fix dst ref loop on input in seg6 lwt
Prevent a dst ref loop on input in seg6_iptunnel.
Fixes: af4a2209b1 ("ipv6: sr: use dst_cache in seg6_input")
Cc: David Lebrun <dlebrun@google.com>
Cc: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									1cf9631d83
								
							
						
					
					
						commit
						c64a0727f9
					
				
					 1 changed files with 12 additions and 2 deletions
				
			
		| 
						 | 
					@ -472,10 +472,18 @@ static int seg6_input_core(struct net *net, struct sock *sk,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dst_entry *orig_dst = skb_dst(skb);
 | 
						struct dst_entry *orig_dst = skb_dst(skb);
 | 
				
			||||||
	struct dst_entry *dst = NULL;
 | 
						struct dst_entry *dst = NULL;
 | 
				
			||||||
 | 
						struct lwtunnel_state *lwtst;
 | 
				
			||||||
	struct seg6_lwt *slwt;
 | 
						struct seg6_lwt *slwt;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
 | 
						/* We cannot dereference "orig_dst" once ip6_route_input() or
 | 
				
			||||||
 | 
						 * skb_dst_drop() is called. However, in order to detect a dst loop, we
 | 
				
			||||||
 | 
						 * need the address of its lwtstate. So, save the address of lwtstate
 | 
				
			||||||
 | 
						 * now and use it later as a comparison.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						lwtst = orig_dst->lwtstate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slwt = seg6_lwt_lwtunnel(lwtst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local_bh_disable();
 | 
						local_bh_disable();
 | 
				
			||||||
	dst = dst_cache_get(&slwt->cache);
 | 
						dst = dst_cache_get(&slwt->cache);
 | 
				
			||||||
| 
						 | 
					@ -490,7 +498,9 @@ static int seg6_input_core(struct net *net, struct sock *sk,
 | 
				
			||||||
	if (!dst) {
 | 
						if (!dst) {
 | 
				
			||||||
		ip6_route_input(skb);
 | 
							ip6_route_input(skb);
 | 
				
			||||||
		dst = skb_dst(skb);
 | 
							dst = skb_dst(skb);
 | 
				
			||||||
		if (!dst->error) {
 | 
					
 | 
				
			||||||
 | 
							/* cache only if we don't create a dst reference loop */
 | 
				
			||||||
 | 
							if (!dst->error && lwtst != dst->lwtstate) {
 | 
				
			||||||
			local_bh_disable();
 | 
								local_bh_disable();
 | 
				
			||||||
			dst_cache_set_ip6(&slwt->cache, dst,
 | 
								dst_cache_set_ip6(&slwt->cache, dst,
 | 
				
			||||||
					  &ipv6_hdr(skb)->saddr);
 | 
										  &ipv6_hdr(skb)->saddr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue