linux/net/ipv4
Neal Cardwell 736c74dc60 tcp: fix tcp_rcv_fastopen_synack() to enter TCP_CA_Loss for failed TFO
[ Upstream commit 5dfe9d2739 ]

Testing determined that the recent commit 9e046bb111 ("tcp: clear
tp->retrans_stamp in tcp_rcv_fastopen_synack()") has a race, and does
not always ensure retrans_stamp is 0 after a TFO payload retransmit.

If transmit completion for the SYN+data skb happens after the client
TCP stack receives the SYNACK (which sometimes happens), then
retrans_stamp can erroneously remain non-zero for the lifetime of the
connection, causing a premature ETIMEDOUT later.

Testing and tracing showed that the buggy scenario is the following
somewhat tricky sequence:

+ Client attempts a TFO handshake. tcp_send_syn_data() sends SYN + TFO
  cookie + data in a single packet in the syn_data skb. It hands the
  syn_data skb to tcp_transmit_skb(), which makes a clone. Crucially,
  it then reuses the same original (non-clone) syn_data skb,
  transforming it by advancing the seq by one byte and removing the
  FIN bit, and enques the resulting payload-only skb in the
  sk->tcp_rtx_queue.

+ Client sets retrans_stamp to the start time of the three-way
  handshake.

+ Cookie mismatches or server has TFO disabled, and server only ACKs
  SYN.

+ tcp_ack() sees SYN is acked, tcp_clean_rtx_queue() clears
  retrans_stamp.

+ Since the client SYN was acked but not the payload, the TFO failure
  code path in tcp_rcv_fastopen_synack() tries to retransmit the
  payload skb.  However, in some cases the transmit completion for the
  clone of the syn_data (which had SYN + TFO cookie + data) hasn't
  happened.  In those cases, skb_still_in_host_queue() returns true
  for the retransmitted TFO payload, because the clone of the syn_data
  skb has not had its tx completetion.

+ Because skb_still_in_host_queue() finds skb_fclone_busy() is true,
  it sets the TSQ_THROTTLED bit and the retransmit does not happen in
  the tcp_rcv_fastopen_synack() call chain.

+ The tcp_rcv_fastopen_synack() code next implicitly assumes the
  retransmit process is finished, and sets retrans_stamp to 0 to clear
  it, but this is later overwritten (see below).

+ Later, upon tx completion, tcp_tsq_write() calls
  tcp_xmit_retransmit_queue(), which puts the retransmit in flight and
  sets retrans_stamp to a non-zero value.

+ The client receives an ACK for the retransmitted TFO payload data.

+ Since we're in CA_Open and there are no dupacks/SACKs/DSACKs/ECN to
  make tcp_ack_is_dubious() true and make us call
  tcp_fastretrans_alert() and reach a code path that clears
  retrans_stamp, retrans_stamp stays nonzero.

+ Later, if there is a TLP, RTO, RTO sequence, then the connection
  will suffer an early ETIMEDOUT due to the erroneously ancient
  retrans_stamp.

The fix: this commit refactors the code to have
tcp_rcv_fastopen_synack() retransmit by reusing the relevant parts of
tcp_simple_retransmit() that enter CA_Loss (without changing cwnd) and
call tcp_xmit_retransmit_queue(). We have tcp_simple_retransmit() and
tcp_rcv_fastopen_synack() share code in this way because in both cases
we get a packet indicating non-congestion loss (MTU reduction or TFO
failure) and thus in both cases we want to retransmit as many packets
as cwnd allows, without reducing cwnd. And given that retransmits will
set retrans_stamp to a non-zero value (and may do so in a later
calling context due to TSQ), we also want to enter CA_Loss so that we
track when all retransmitted packets are ACked and clear retrans_stamp
when that happens (to ensure later recurring RTOs are using the
correct retrans_stamp and don't declare ETIMEDOUT prematurely).

Fixes: 9e046bb111 ("tcp: clear tp->retrans_stamp in tcp_rcv_fastopen_synack()")
Fixes: a7abf3cd76 ("tcp: consider using standard rtx logic in tcp_rcv_fastopen_synack()")
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Link: https://patch.msgid.link/20240624144323.2371403-1-ncardwell.sw@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
History 2024-07-05 09:31:47 +02:00
..
bpfilter net: Revert "net: optimize the sockptr_t for unified kernel/user address spaces" 2020-08-10 12:06:44 -07:00
netfilter netfilter: tproxy: bail out if IP has been disabled on the device 2024-06-12 11:03:57 +02:00
af_inet.c net: relax socket state check at accept time. 2024-06-12 11:03:53 +02:00
ah4.c xfrm: ah: add extack to ah_init_state, ah6_init_state 2022-09-29 07:17:59 +02:00
arp.c arp: Prevent overflow in arp_req_get(). 2024-03-01 13:26:39 +01:00
bpf_tcp_ca.c bpf: Use 0 instead of NOT_INIT for btf_struct_access() writes 2022-09-10 17:27:32 -07:00
cipso_ipv4.c cipso: fix total option length computation 2024-06-27 13:46:18 +02:00
datagram.c ipv4: fix data-races around inet->inet_id 2023-08-30 16:11:02 +02:00
devinet.c ipv4: properly combine dev_base_seq and ipv4.dev_addr_genid 2024-03-01 13:26:36 +01:00
esp4.c net: ipv4: fix return value check in esp_remove_trailer 2023-10-25 12:03:06 +02:00
esp4_offload.c xfrm: Linearize the skb after offloading if needed. 2023-06-28 11:12:29 +02:00
fib_frontend.c ipv4: Fix incorrect table ID in IOCTL path 2023-03-22 13:33:50 +01:00
fib_lookup.h Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net 2022-02-17 11:44:20 -08:00
fib_notifier.c net: ipv4: remove superfluous header files from fib_notifier.c 2021-09-28 17:32:56 -07:00
fib_rules.c ipv4: remove unnecessary type castings 2022-04-30 15:12:58 +01:00
fib_semantics.c ipv4/fib: send notify when delete source address routes 2023-10-25 12:03:11 +02:00
fib_trie.c ipv4/fib: send notify when delete source address routes 2023-10-25 12:03:11 +02:00
fou.c genetlink: start to validate reserved header bytes 2022-08-29 12:47:15 +01:00
gre_demux.c net: Remove the member netns_ok 2021-05-17 15:29:35 -07:00
gre_offload.c net: gro: skb_gro_header helper function 2022-08-25 10:33:21 +02:00
icmp.c icmp: prevent possible NULL dereferences from icmp_build_probe() 2024-05-02 16:29:23 +02:00
igmp.c ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet 2023-12-08 08:51:17 +01:00
inet_connection_sock.c Fix race for duplicate reqsk on identical SYN 2024-07-05 09:31:46 +02:00
inet_diag.c inet_diag: annotate data-races around inet_diag_table[] 2024-03-26 18:20:31 -04:00
inet_fragment.c inet: inet_defrag: prevent sk release while still in use 2024-04-10 16:28:23 +02:00
inet_hashtables.c net: remove duplicate reuseport_lookup functions 2024-06-12 11:03:12 +02:00
inet_timewait_sock.c tcp: Fix NEW_SYN_RECV handling in inet_twsk_purge() 2024-03-26 18:20:58 -04:00
inetpeer.c inetpeer: Fix data-races around sysctl. 2022-07-08 12:10:33 +01:00
ip_forward.c ip: Fix data-races around sysctl_ip_fwd_update_priority. 2022-07-15 11:49:55 +01:00
ip_fragment.c inet: inet_defrag: prevent sk release while still in use 2024-04-10 16:28:23 +02:00
ip_gre.c erspan: make sure erspan_base_hdr is present in skb->head 2024-04-10 16:28:27 +02:00
ip_input.c ipv4: ignore dst hint for multipath routes 2023-09-19 12:28:01 +02:00
ip_options.c ipv4: drop fragmentation code from ip_options_build() 2022-01-29 17:53:07 +00:00
ip_output.c net: ipv4: fix a memleak in ip_setup_cork 2024-02-05 20:13:02 +00:00
ip_sockglue.c ipmr: fix kernel panic when forwarding mcast packets 2024-02-05 20:13:00 +00:00
ip_tunnel.c net: ip_tunnel: make sure to pull inner header in ip_tunnel_rcv() 2024-03-26 18:20:41 -04:00
ip_tunnel_core.c tunnels: fix out of bounds access when building IPv6 PMTU error 2024-02-16 19:06:26 +01:00
ip_vti.c ip_vti: fix potential slab-use-after-free in decode_session6 2023-08-23 17:52:32 +02:00
ipcomp.c xfrm: ipcomp: add extack to ipcomp{4,6}_init_state 2022-09-29 07:18:00 +02:00
ipconfig.c Driver core / kernfs changes for 6.0-rc1 2022-08-04 11:31:20 -07:00
ipip.c net: Add helper function to parse netlink msg of ip_tunnel_parm 2022-10-03 07:59:06 +01:00
ipmr.c ipmr: fix incorrect parameter validation in the ip_mroute_getsockopt() function 2024-03-26 18:20:42 -04:00
ipmr_base.c ipmr: adopt rcu_read_lock() in mr_dump() 2022-06-24 11:34:38 +01:00
Kconfig tcp: configurable source port perturb table size 2022-11-16 13:02:04 +00:00
Makefile bpf: Clean up sockmap related Kconfigs 2021-02-26 12:28:03 -08:00
metrics.c ipv4: prevent potential spectre v1 gadget in ip_metrics_convert() 2023-02-01 08:34:45 +01:00
netfilter.c netfilter: Use l3mdev flow key when re-routing mangled packets 2022-05-16 13:03:29 +02:00
netlink.c treewide: Add SPDX license identifier for missed files 2019-05-21 10:50:45 +02:00
nexthop.c neighbour: switch to standard rcu, instead of rcu_bh 2023-10-10 22:00:42 +02:00
ping.c ping: Fix potentail NULL deref for /proc/net/icmp. 2023-04-13 16:55:24 +02:00
proc.c tcp: Don't allocate tcp_death_row outside of struct netns_ipv4. 2022-09-20 10:21:49 -07:00
protocol.c net: Remove the member netns_ok 2021-05-17 15:29:35 -07:00
raw.c ipv4: raw: Fix sending packets from raw sockets via IPsec tunnels 2024-03-26 18:21:00 -04:00
raw_diag.c raw: Fix NULL deref in raw_get_next(). 2023-04-13 16:55:23 +02:00
route.c net: fix __dst_negative_advice() race 2024-06-16 13:41:40 +02:00
syncookies.c tcp: fix cookie_init_timestamp() overflows 2023-11-20 11:51:54 +01:00
sysctl_net_ipv4.c tcp: enforce receive buffer memory limits by allowing the tcp window to shrink 2023-10-19 23:08:54 +02:00
tcp.c tcp: count CLOSE-WAIT sockets for TCP_MIB_CURRESTAB 2024-06-21 14:35:34 +02:00
tcp_bbr.c bpf: Switch to new kfunc flags infrastructure 2022-07-21 20:59:42 -07:00
tcp_bic.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_bpf.c tcp_bpf: properly release resources on error paths 2023-10-25 12:03:13 +02:00
tcp_cdg.c Random number generator fixes for Linux 6.1-rc1. 2022-10-16 15:27:07 -07:00
tcp_cong.c tcp: Add tracepoint for tcp_set_ca_state 2022-04-07 20:33:15 -07:00
tcp_cubic.c bpf: Switch to new kfunc flags infrastructure 2022-07-21 20:59:42 -07:00
tcp_dctcp.c tcp: Fix shift-out-of-bounds in dctcp_update_alpha(). 2024-06-12 11:03:51 +02:00
tcp_dctcp.h tcp: refactor DCTCP ECN ACK handling 2018-10-10 22:26:00 -07:00
tcp_diag.c tcp: Access &tcp_hashinfo via net. 2022-09-20 10:21:49 -07:00
tcp_fastopen.c tcp: annotate data-races around fastopenq.max_qlen 2023-07-27 08:50:49 +02:00
tcp_highspeed.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_htcp.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_hybla.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_illinois.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_input.c tcp: fix tcp_rcv_fastopen_synack() to enter TCP_CA_Loss for failed TFO 2024-07-05 09:31:47 +02:00
tcp_ipv4.c tcp: avoid premature drops in tcp_add_backlog() 2024-06-12 11:03:13 +02:00
tcp_lp.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_metrics.c tcp_metrics: do not create an entry from tcp_init_metrics() 2023-11-20 11:51:53 +01:00
tcp_minisocks.c rds: tcp: Fix use-after-free of net in reqsk_timer_handler(). 2024-03-26 18:20:58 -04:00
tcp_nv.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_offload.c tcp: gso: really support BIG TCP 2023-06-14 11:15:20 +02:00
tcp_output.c tcp: defer shutdown(SEND_SHUTDOWN) for TCP_SYN_RECV sockets 2024-05-17 11:56:11 +02:00
tcp_rate.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net 2022-04-28 13:02:01 -07:00
tcp_recovery.c tcp: fix excessive TLP and RACK timeouts from HZ rounding 2023-10-25 12:03:06 +02:00
tcp_scalable.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_timer.c net: tcp: fix unexcepted socket die when snd_wnd is 0 2023-09-13 09:42:32 +02:00
tcp_ulp.c net/ulp: use consistent error code when blocking ULP 2023-01-24 07:24:43 +01:00
tcp_vegas.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_vegas.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
tcp_veno.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_westwood.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tcp_yeah.c tcp: add accessors to read/set tp->snd_cwnd 2022-04-06 12:05:41 -07:00
tunnel4.c net: Remove the member netns_ok 2021-05-17 15:29:35 -07:00
udp.c udp: Avoid call to compute_score on multiple sites 2024-06-12 11:03:12 +02:00
udp_bpf.c bpf, sockmap: Fix an infinite loop error when len is 0 in tcp_bpf_recvmsg_parser() 2023-03-17 08:50:24 +01:00
udp_diag.c net: Use nlmsg_unicast() instead of netlink_unicast() 2021-07-13 09:28:29 -07:00
udp_impl.h net: remove noblock parameter from recvmsg() entities 2022-04-12 15:00:25 +02:00
udp_offload.c net: gro: add flush check in udp_gro_receive_segment 2024-05-17 11:56:02 +02:00
udp_tunnel_core.c udp: lockless UDP_ENCAP_L2TPINUDP / UDP_GRO 2024-01-10 17:10:28 +01:00
udp_tunnel_nic.c udp_tunnel: Fix end of loop test in udp_tunnel_nic_unregister() 2022-02-23 12:35:00 +00:00
udp_tunnel_stub.c udp_tunnel: add central NIC RX port offload infrastructure 2020-07-10 13:54:00 -07:00
udplite.c udplite: Fix NULL pointer dereference in __sk_mem_raise_allocated(). 2023-05-30 14:03:20 +01:00
xfrm4_input.c xfrm: Preserve vlan tags for transport mode software GRO 2024-05-17 11:56:10 +02:00
xfrm4_output.c xfrm: fix unused variable warning if CONFIG_NETFILTER=n 2020-05-11 15:12:27 +02:00
xfrm4_policy.c net: rename reference+tracking helpers 2022-06-09 21:52:55 -07:00
xfrm4_protocol.c net: xfrm: unexport __init-annotated xfrm4_protocol_init() 2022-06-08 10:10:13 -07:00
xfrm4_state.c xfrm: remove output_finish indirection from xfrm_state_afinfo 2020-05-06 09:40:08 +02:00
xfrm4_tunnel.c xfrm: tunnel: add extack to ipip_init_state, xfrm6_tunnel_init_state 2022-09-29 07:18:00 +02:00