Commit 65745342 authored by Eric Dumazet's avatar Eric Dumazet Committed by Greg Kroah-Hartman

net: Fix sock_wfree() race

[ Upstream commit d99927f4 ]

Commit 2b85a34e
(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: default avatarJike Song <albcamus@gmail.com>
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e3d38b57
...@@ -1218,17 +1218,22 @@ void __init sk_init(void) ...@@ -1218,17 +1218,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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment