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)
 | 
			
		||||
{
 | 
			
		||||
	struct sock *sk = skb->sk;
 | 
			
		||||
	int res;
 | 
			
		||||
	unsigned int len = skb->truesize;
 | 
			
		||||
 | 
			
		||||
	/* In case it might be waiting for more memory. */
 | 
			
		||||
	res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc);
 | 
			
		||||
	if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE))
 | 
			
		||||
		sk->sk_write_space(sk);
 | 
			
		||||
	if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) {
 | 
			
		||||
		/*
 | 
			
		||||
	 * if sk_wmem_alloc reached 0, we are last user and should
 | 
			
		||||
	 * free this sock, as sk_free() call could not do it.
 | 
			
		||||
		 * Keep a reference on sk_wmem_alloc, this will be released
 | 
			
		||||
		 * after sk_write_space() call
 | 
			
		||||
		 */
 | 
			
		||||
	if (res == 0)
 | 
			
		||||
		atomic_sub(len - 1, &sk->sk_wmem_alloc);
 | 
			
		||||
		sk->sk_write_space(sk);
 | 
			
		||||
		len = 1;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * if sk_wmem_alloc reaches 0, we must finish what sk_free()
 | 
			
		||||
	 * could not do because of in-flight packets
 | 
			
		||||
	 */
 | 
			
		||||
	if (atomic_sub_and_test(len, &sk->sk_wmem_alloc))
 | 
			
		||||
		__sk_free(sk);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(sock_wfree);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue