diff options
author | Guillaume Nault <gnault@redhat.com> | 2019-03-08 22:09:47 +0100 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-09-06 15:49:42 +0800 |
commit | 3d4ab75bb0a767927ca411f790164f35605b745f (patch) | |
tree | 8e80cdcf1e7851552116e34e71c716d50dcb148a /net/ipv4/syncookies.c | |
parent | f5e7555bec7c27e19bb57d91ba21da394e25b3c9 (diff) |
tcp: handle inet_csk_reqsk_queue_add() failures
[ Upstream commit 9d3e1368bb45893a75a5dfb7cd21fdebfa6b47af ]
Commit 7716682cc58e ("tcp/dccp: fix another race at listener
dismantle") let inet_csk_reqsk_queue_add() fail, and adjusted
{tcp,dccp}_check_req() accordingly. However, TFO and syncookies
weren't modified, thus leaking allocated resources on error.
Contrary to tcp_check_req(), in both syncookies and TFO cases,
we need to drop the request socket. Also, since the child socket is
created with inet_csk_clone_lock(), we have to unlock it and drop an
extra reference (->sk_refcount is initially set to 2 and
inet_csk_reqsk_queue_add() drops only one ref).
For TFO, we also need to revert the work done by tcp_try_fastopen()
(with reqsk_fastopen_remove()).
Fixes: 7716682cc58e ("tcp/dccp: fix another race at listener dismantle")
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit bb73b637993bd77087c0f3e56e86a040f230e435)
Diffstat (limited to 'net/ipv4/syncookies.c')
-rw-r--r-- | net/ipv4/syncookies.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 77cf32a80952..2f871424925e 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -216,7 +216,12 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, refcount_set(&req->rsk_refcnt, 1); tcp_sk(child)->tsoffset = tsoff; sock_rps_save_rxhash(child, skb); - inet_csk_reqsk_queue_add(sk, req, child); + if (!inet_csk_reqsk_queue_add(sk, req, child)) { + bh_unlock_sock(child); + sock_put(child); + child = NULL; + reqsk_put(req); + } } else { reqsk_free(req); } |