forked from mirrors/linux
		
	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
	
	 Eric Dumazet
						Eric Dumazet