mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: adjust skb->truesize in pskb_expand_head()
Slava Shwartsman reported a warning in skb_try_coalesce(), when we detect skb->truesize is completely wrong. In his case, issue came from IPv6 reassembly coping with malicious datagrams, that forced various pskb_may_pull() to reallocate a bigger skb->head than the one allocated by NIC driver before entering GRO layer. Current code does not change skb->truesize, leaving this burden to callers if they care enough. Blindly changing skb->truesize in pskb_expand_head() is not easy, as some producers might track skb->truesize, for example in xmit path for back pressure feedback (sk->sk_wmem_alloc) We can detect the cases where it should be safe to change skb->truesize : 1) skb is not attached to a socket. 2) If it is attached to a socket, destructor is sock_edemux() My audit gave only two callers doing their own skb->truesize manipulation. I had to remove skb parameter in sock_edemux macro when CONFIG_INET is not set to avoid a compile error. Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Slava Shwartsman <slavash@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									b41fd8fdef
								
							
						
					
					
						commit
						158f323b98
					
				
					 4 changed files with 15 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -1534,7 +1534,7 @@ void sock_efree(struct sk_buff *skb);
 | 
			
		|||
#ifdef CONFIG_INET
 | 
			
		||||
void sock_edemux(struct sk_buff *skb);
 | 
			
		||||
#else
 | 
			
		||||
#define sock_edemux(skb) sock_efree(skb)
 | 
			
		||||
#define sock_edemux sock_efree
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int sock_setsockopt(struct socket *sock, int level, int op,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1192,10 +1192,10 @@ EXPORT_SYMBOL(__pskb_copy_fclone);
 | 
			
		|||
int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 | 
			
		||||
		     gfp_t gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	u8 *data;
 | 
			
		||||
	int size = nhead + skb_end_offset(skb) + ntail;
 | 
			
		||||
	int i, osize = skb_end_offset(skb);
 | 
			
		||||
	int size = osize + nhead + ntail;
 | 
			
		||||
	long off;
 | 
			
		||||
	u8 *data;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(nhead < 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1257,6 +1257,14 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 | 
			
		|||
	skb->hdr_len  = 0;
 | 
			
		||||
	skb->nohdr    = 0;
 | 
			
		||||
	atomic_set(&skb_shinfo(skb)->dataref, 1);
 | 
			
		||||
 | 
			
		||||
	/* It is not generally safe to change skb->truesize.
 | 
			
		||||
	 * For the moment, we really care of rx path, or
 | 
			
		||||
	 * when skb is orphaned (not attached to a socket).
 | 
			
		||||
	 */
 | 
			
		||||
	if (!skb->sk || skb->destructor == sock_edemux)
 | 
			
		||||
		skb->truesize += size - osize;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
nofrags:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1210,11 +1210,9 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
 | 
			
		|||
		skb = nskb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!pskb_expand_head(skb, 0, -delta,
 | 
			
		||||
	pskb_expand_head(skb, 0, -delta,
 | 
			
		||||
			 (allocation & ~__GFP_DIRECT_RECLAIM) |
 | 
			
		||||
			      __GFP_NOWARN | __GFP_NORETRY))
 | 
			
		||||
		skb->truesize -= delta;
 | 
			
		||||
 | 
			
		||||
			 __GFP_NOWARN | __GFP_NORETRY);
 | 
			
		||||
	return skb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -618,8 +618,6 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
 | 
			
		|||
 | 
			
		||||
		if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		skb->truesize += head_need;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (encaps_data) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue