Message ID | 1505170718.15310.134.camel@edumazet-glaptop3.roam.corp.google.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
Series | [net] tcp/dccp: remove reqsk_put() from inet_child_forget() | expand |
From: Eric Dumazet <eric.dumazet@gmail.com> Date: Mon, 11 Sep 2017 15:58:38 -0700 > From: Eric Dumazet <edumazet@google.com> > > Back in linux-4.4, I inadvertently put a call to reqsk_put() in > inet_child_forget(), forgetting it could be called from two different > points. > > In the case it is called from inet_csk_reqsk_queue_add(), we want to > keep the reference on the request socket, since it is released later by > the caller (tcp_v{4|6}_rcv()) > > This bug never showed up because atomic_dec_and_test() was not signaling > the underflow, and SLAB_DESTROY_BY RCU semantic for request sockets > prevented the request to be put in quarantine. > > Recent conversion of socket refcount from atomic_t to refcount_t finally > exposed the bug. > > So move the reqsk_put() to inet_csk_listen_stop() to fix this. > > Thanks to Shankara Pailoor for using syzkaller and providing > a nice set of .config and C repro. ... > Fixes: ebb516af60e1 ("tcp/dccp: fix race at listener dismantle phase") > Signed-off-by: Eric Dumazet <edumazet@google.com> > Reported-by: Shankara Pailoor <sp3485@columbia.edu> > Tested-by: Shankara Pailoor <sp3485@columbia.edu> Applied and queued up for -stable. Thanks.
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 4089c013cb03b12e31ddffbb7ae903542c012ae0..b9c64b40a83af1e151f553ba0e624fae5060ffd0 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -916,7 +916,6 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, tcp_sk(child)->fastopen_rsk = NULL; } inet_csk_destroy_sock(child); - reqsk_put(req); } struct sock *inet_csk_reqsk_queue_add(struct sock *sk, @@ -987,6 +986,7 @@ void inet_csk_listen_stop(struct sock *sk) sock_hold(child); inet_child_forget(sk, req, child); + reqsk_put(req); bh_unlock_sock(child); local_bh_enable(); sock_put(child);