aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_ipv4.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-10-22 11:20:46 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-23 08:42:21 -0400
commit5e0724d027f0548511a2165a209572d48fe7a4c8 (patch)
tree709301be9b56652004047b89f4467b3c917814cd /net/ipv4/tcp_ipv4.c
parent7b1311807f3d3eb8bef3ccc53127838b3bea3771 (diff)
tcp/dccp: fix hashdance race for passive sessions
Multiple cpus can process duplicates of incoming ACK messages matching a SYN_RECV request socket. This is a rare event under normal operations, but definitely can happen. Only one must win the race, otherwise corruption would occur. To fix this without adding new atomic ops, we use logic in inet_ehash_nolisten() to detect the request was present in the same ehash bucket where we try to insert the new child. If request socket was not found, we have to undo the child creation. This actually removes a spin_lock()/spin_unlock() pair in reqsk_queue_unlink() for the fast path. Fixes: e994b2f0fb92 ("tcp: do not lock listener to process SYN packets") Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table") Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r--net/ipv4/tcp_ipv4.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 30dd45c1f568..1c2648bbac4b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1247,7 +1247,9 @@ EXPORT_SYMBOL(tcp_v4_conn_request);
1247 */ 1247 */
1248struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, 1248struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
1249 struct request_sock *req, 1249 struct request_sock *req,
1250 struct dst_entry *dst) 1250 struct dst_entry *dst,
1251 struct request_sock *req_unhash,
1252 bool *own_req)
1251{ 1253{
1252 struct inet_request_sock *ireq; 1254 struct inet_request_sock *ireq;
1253 struct inet_sock *newinet; 1255 struct inet_sock *newinet;
@@ -1323,7 +1325,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
1323 1325
1324 if (__inet_inherit_port(sk, newsk) < 0) 1326 if (__inet_inherit_port(sk, newsk) < 0)
1325 goto put_and_exit; 1327 goto put_and_exit;
1326 __inet_hash_nolisten(newsk, NULL); 1328 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
1327 1329
1328 return newsk; 1330 return newsk;
1329 1331