net: Fix sock_wfree() race
Commit 2b85a34e91
(net: No more expensive sock_hold()/sock_put() on each tx)
opens a window in sock_wfree() where another cpu
might free the socket we are working on.
A fix is to call sk->sk_write_space(sk) while still
holding a reference on sk.
Reported-by: Jike Song <albcamus@gmail.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
	
	
This commit is contained in:
		
					parent
					
						
							
								b7058842c9
							
						
					
				
			
			
				commit
				
					
						d99927f4d9
					
				
			
		
					 1 changed files with 12 additions and 7 deletions
				
			
		| 
						 | 
					@ -1228,17 +1228,22 @@ void __init sk_init(void)
 | 
				
			||||||
void sock_wfree(struct sk_buff *skb)
 | 
					void sock_wfree(struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sock *sk = skb->sk;
 | 
						struct sock *sk = skb->sk;
 | 
				
			||||||
	int res;
 | 
						unsigned int len = skb->truesize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* In case it might be waiting for more memory. */
 | 
						if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) {
 | 
				
			||||||
	res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc);
 | 
							/*
 | 
				
			||||||
	if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE))
 | 
							 * Keep a reference on sk_wmem_alloc, this will be released
 | 
				
			||||||
 | 
							 * after sk_write_space() call
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							atomic_sub(len - 1, &sk->sk_wmem_alloc);
 | 
				
			||||||
		sk->sk_write_space(sk);
 | 
							sk->sk_write_space(sk);
 | 
				
			||||||
 | 
							len = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * if sk_wmem_alloc reached 0, we are last user and should
 | 
						 * if sk_wmem_alloc reaches 0, we must finish what sk_free()
 | 
				
			||||||
	 * free this sock, as sk_free() call could not do it.
 | 
						 * could not do because of in-flight packets
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (res == 0)
 | 
						if (atomic_sub_and_test(len, &sk->sk_wmem_alloc))
 | 
				
			||||||
		__sk_free(sk);
 | 
							__sk_free(sk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(sock_wfree);
 | 
					EXPORT_SYMBOL(sock_wfree);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue