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
 | 
					#ifdef CONFIG_INET
 | 
				
			||||||
void sock_edemux(struct sk_buff *skb);
 | 
					void sock_edemux(struct sk_buff *skb);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define sock_edemux(skb) sock_efree(skb)
 | 
					#define sock_edemux sock_efree
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int sock_setsockopt(struct socket *sock, int level, int op,
 | 
					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,
 | 
					int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 | 
				
			||||||
		     gfp_t gfp_mask)
 | 
							     gfp_t gfp_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i, osize = skb_end_offset(skb);
 | 
				
			||||||
	u8 *data;
 | 
						int size = osize + nhead + ntail;
 | 
				
			||||||
	int size = nhead + skb_end_offset(skb) + ntail;
 | 
					 | 
				
			||||||
	long off;
 | 
						long off;
 | 
				
			||||||
 | 
						u8 *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(nhead < 0);
 | 
						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->hdr_len  = 0;
 | 
				
			||||||
	skb->nohdr    = 0;
 | 
						skb->nohdr    = 0;
 | 
				
			||||||
	atomic_set(&skb_shinfo(skb)->dataref, 1);
 | 
						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;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nofrags:
 | 
					nofrags:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1210,11 +1210,9 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
 | 
				
			||||||
		skb = nskb;
 | 
							skb = nskb;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pskb_expand_head(skb, 0, -delta,
 | 
						pskb_expand_head(skb, 0, -delta,
 | 
				
			||||||
			 (allocation & ~__GFP_DIRECT_RECLAIM) |
 | 
								 (allocation & ~__GFP_DIRECT_RECLAIM) |
 | 
				
			||||||
			      __GFP_NOWARN | __GFP_NORETRY))
 | 
								 __GFP_NOWARN | __GFP_NORETRY);
 | 
				
			||||||
		skb->truesize -= delta;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return skb;
 | 
						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))
 | 
							if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		skb->truesize += head_need;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (encaps_data) {
 | 
						if (encaps_data) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue