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
					
				| @ -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)) | ||||
| 	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); | ||||
| 		len = 1; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * if sk_wmem_alloc reached 0, we are last user and should | ||||
| 	 * free this sock, as sk_free() call could not do it. | ||||
| 	 * if sk_wmem_alloc reaches 0, we must finish what sk_free() | ||||
| 	 * could not do because of in-flight packets | ||||
| 	 */ | ||||
| 	if (res == 0) | ||||
| 	if (atomic_sub_and_test(len, &sk->sk_wmem_alloc)) | ||||
| 		__sk_free(sk); | ||||
| } | ||||
| EXPORT_SYMBOL(sock_wfree); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user