diff options
author | Eric Dumazet <edumazet@google.com> | 2015-10-05 00:08:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-05 05:45:24 -0400 |
commit | 7656d842de93fd2d2de7b403062cad757cadf1df (patch) | |
tree | ca3dd9409538fcb415d5e7166269a0e6e89b26b1 /net/ipv4/tcp_input.c | |
parent | 3e087caa23ef36370bfb925d3bbca78e8302d3ce (diff) |
tcp: fix fastopen races vs lockless listener
There are multiple races that need fixes :
1) skb_get() + queue skb + kfree_skb() is racy
An accept() can be done on another cpu, data consumed immediately.
tcp_recvmsg() uses __kfree_skb() as it is assumed all skb found in
socket receive queue are private.
Then the kfree_skb() in tcp_rcv_state_process() uses an already freed skb
2) tcp_reqsk_record_syn() needs to be done before tcp_try_fastopen()
for the same reasons.
3) We want to send the SYNACK before queueing child into accept queue,
otherwise we might reintroduce the ooo issue fixed in
commit 7c85af881044 ("tcp: avoid reorders for TFO passive connections")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 27108757c310..a95c8eb04ff7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -6229,12 +6229,16 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, | |||
6229 | tcp_rsk(req)->txhash = net_tx_rndhash(); | 6229 | tcp_rsk(req)->txhash = net_tx_rndhash(); |
6230 | tcp_openreq_init_rwin(req, sk, dst); | 6230 | tcp_openreq_init_rwin(req, sk, dst); |
6231 | if (!want_cookie) { | 6231 | if (!want_cookie) { |
6232 | fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
6233 | tcp_reqsk_record_syn(sk, req, skb); | 6232 | tcp_reqsk_record_syn(sk, req, skb); |
6233 | fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
6234 | } | 6234 | } |
6235 | if (fastopen_sk) { | 6235 | if (fastopen_sk) { |
6236 | af_ops->send_synack(fastopen_sk, dst, &fl, req, | 6236 | af_ops->send_synack(fastopen_sk, dst, &fl, req, |
6237 | skb_get_queue_mapping(skb), &foc, false); | 6237 | skb_get_queue_mapping(skb), &foc, false); |
6238 | /* Add the child socket directly into the accept queue */ | ||
6239 | inet_csk_reqsk_queue_add(sk, req, fastopen_sk); | ||
6240 | sk->sk_data_ready(sk); | ||
6241 | bh_unlock_sock(fastopen_sk); | ||
6238 | sock_put(fastopen_sk); | 6242 | sock_put(fastopen_sk); |
6239 | } else { | 6243 | } else { |
6240 | tcp_rsk(req)->tfo_listener = false; | 6244 | tcp_rsk(req)->tfo_listener = false; |