mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	mpls: drop skb's dst in mpls_forward()
Commit 394de110a7 ("net: Added pointer check for
dst->ops->neigh_lookup in dst_neigh_lookup_skb") added a test in
dst_neigh_lookup_skb() to avoid a NULL pointer dereference. The root
cause was the MPLS forwarding code, which doesn't call skb_dst_drop()
on incoming packets. That is, if the packet is received from a
collect_md device, it has a metadata_dst attached to it that doesn't
implement any dst_ops function.
To align the MPLS behaviour with IPv4 and IPv6, let's drop the dst in
mpls_forward(). This way, dst_neigh_lookup_skb() doesn't need to test
->neigh_lookup any more. Let's keep a WARN condition though, to
document the precondition and to ease detection of such problems in the
future.
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Link: https://lore.kernel.org/r/f8c2784c13faa54469a2aac339470b1049ca6b63.1604102750.git.gnault@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									6d89076e6e
								
							
						
					
					
						commit
						0992d67bc2
					
				
					 2 changed files with 7 additions and 7 deletions
				
			
		| 
						 | 
					@ -400,13 +400,11 @@ static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, co
 | 
				
			||||||
static inline struct neighbour *dst_neigh_lookup_skb(const struct dst_entry *dst,
 | 
					static inline struct neighbour *dst_neigh_lookup_skb(const struct dst_entry *dst,
 | 
				
			||||||
						     struct sk_buff *skb)
 | 
											     struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct neighbour *n = NULL;
 | 
						struct neighbour *n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON_ONCE(!dst->ops->neigh_lookup))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The packets from tunnel devices (eg bareudp) may have only
 | 
					 | 
				
			||||||
	 * metadata in the dst pointer of skb. Hence a pointer check of
 | 
					 | 
				
			||||||
	 * neigh_lookup is needed.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (dst->ops->neigh_lookup)
 | 
					 | 
				
			||||||
	n = dst->ops->neigh_lookup(dst, skb, NULL);
 | 
						n = dst->ops->neigh_lookup(dst, skb, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return IS_ERR(n) ? NULL : n;
 | 
						return IS_ERR(n) ? NULL : n;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -377,6 +377,8 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
	if (!pskb_may_pull(skb, sizeof(*hdr)))
 | 
						if (!pskb_may_pull(skb, sizeof(*hdr)))
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb_dst_drop(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Read and decode the label */
 | 
						/* Read and decode the label */
 | 
				
			||||||
	hdr = mpls_hdr(skb);
 | 
						hdr = mpls_hdr(skb);
 | 
				
			||||||
	dec = mpls_entry_decode(hdr);
 | 
						dec = mpls_entry_decode(hdr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue