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 7c85af8810 ("tcp: avoid reorders for TFO passive connections")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
3e087caa23
commit
7656d842de
@@ -6229,12 +6229,16 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
|
||||
tcp_rsk(req)->txhash = net_tx_rndhash();
|
||||
tcp_openreq_init_rwin(req, sk, dst);
|
||||
if (!want_cookie) {
|
||||
fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst);
|
||||
tcp_reqsk_record_syn(sk, req, skb);
|
||||
fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst);
|
||||
}
|
||||
if (fastopen_sk) {
|
||||
af_ops->send_synack(fastopen_sk, dst, &fl, req,
|
||||
skb_get_queue_mapping(skb), &foc, false);
|
||||
/* Add the child socket directly into the accept queue */
|
||||
inet_csk_reqsk_queue_add(sk, req, fastopen_sk);
|
||||
sk->sk_data_ready(sk);
|
||||
bh_unlock_sock(fastopen_sk);
|
||||
sock_put(fastopen_sk);
|
||||
} else {
|
||||
tcp_rsk(req)->tfo_listener = false;
|
||||
|
||||
Reference in New Issue
Block a user