From: Zhiling Zou tcp_synack_retries supplies the SYN-ACK retry limit used by request socket timers. The same effective limit can also come from TCP_SYNCNT through icsk_syn_retries, while TCP_DEFER_ACCEPT can keep an ACKed request alive until rskq_defer_accept is reached. The request socket timeout counter is incremented before it is used to compute the next timeout. tcp_reqsk_timeout() and the Fast Open SYN-ACK timer shift req->timeout by req->num_timeout. Excessive retry or defer-accept limits can therefore drive these timer paths into invalid shift counts before the request expires. Clamp the effective retry and defer-accept limits in the regular request socket timer path, clamp the Fast Open retry limit, and make the request socket timeout helper saturate before shifting. This keeps sysctl writes unchanged while bounding the timer calculations. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Reported-by: Vega Assisted-by: Codex:gpt-5.4 Signed-off-by: Zhiling Zou Signed-off-by: Ren Wei --- Changes in v4: - Drop the tcp_synack_retries sysctl maximum to preserve existing user-space behavior, and keep the runtime clamps at the timer usage sites. - v3 Link: https://lore.kernel.org/all/20260702095324.2995243-1-n05ec@lzu.edu.cn/ Changes in v3: - Order local variables in tcp_reqsk_timeout_sk() by reverse Christmas tree. - v2 Link: https://lore.kernel.org/all/20260630035009.55201-1-n05ec@lzu.edu.cn/ Changes in v2: - Keep the existing max_retries calculation in tcp_fastopen_synack_timer() and only add the clamp, avoiding code churn. - v1 Link: https://lore.kernel.org/all/02e24eb83639e9d7ecc623f000c60254bb5c40a5.1782643946.git.roxy520tt@gmail.com/ include/net/tcp.h | 19 +++++++++++++++---- net/ipv4/inet_connection_sock.c | 6 +++++- net/ipv4/tcp_timer.c | 3 ++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 6d376ea4d1c0..ee78436b8964 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -183,6 +183,7 @@ static_assert((1 << ATO_BITS) > TCP_DELACK_MAX); #define MAX_TCP_KEEPINTVL 32767 #define MAX_TCP_KEEPCNT 127 #define MAX_TCP_SYNCNT 127 +#define MAX_TCP_SYNACK_RETRIES 63 /* Ensure that TCP PAWS checks are relaxed after ~2147 seconds * to avoid overflows. This assumes a clock smaller than 1 Mhz. @@ -882,12 +883,22 @@ static inline u32 __tcp_set_rto(const struct tcp_sock *tp) return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us); } -static inline unsigned long tcp_reqsk_timeout(struct request_sock *req) +static inline unsigned long tcp_reqsk_timeout_sk(const struct sock *sk, + struct request_sock *req) { - u64 timeout = (u64)req->timeout << req->num_timeout; + u32 rto_max = tcp_rto_max(sk); + u64 timeout = req->timeout; + + if (req->num_timeout >= BITS_PER_TYPE(u64) || + timeout > U64_MAX >> req->num_timeout) + return rto_max; + + return (unsigned long)min_t(u64, timeout << req->num_timeout, rto_max); +} - return (unsigned long)min_t(u64, timeout, - tcp_rto_max(req->rsk_listener)); +static inline unsigned long tcp_reqsk_timeout(struct request_sock *req) +{ + return tcp_reqsk_timeout_sk(req->rsk_listener, req); } u32 tcp_delack_max(const struct sock *sk); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 56902bba5483..b74212bae3dd 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -1056,6 +1056,8 @@ static void reqsk_timer_handler(struct timer_list *t) net = sock_net(sk_listener); max_syn_ack_retries = READ_ONCE(icsk->icsk_syn_retries) ? : READ_ONCE(net->ipv4.sysctl_tcp_synack_retries); + max_syn_ack_retries = min_t(int, max_syn_ack_retries, + MAX_TCP_SYNACK_RETRIES); /* Normally all the openreqs are young and become mature * (i.e. converted to established socket) for first timeout. * If synack was not acknowledged for 1 second, it means @@ -1086,7 +1088,9 @@ static void reqsk_timer_handler(struct timer_list *t) } } - syn_ack_recalc(req, max_syn_ack_retries, READ_ONCE(queue->rskq_defer_accept), + syn_ack_recalc(req, max_syn_ack_retries, + min_t(u8, READ_ONCE(queue->rskq_defer_accept), + MAX_TCP_SYNACK_RETRIES), &expire, &resend); tcp_syn_ack_timeout(req); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index bf171b5e1eb3..bbedf2b9e1bc 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -467,6 +467,7 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req) */ max_retries = READ_ONCE(icsk->icsk_syn_retries) ? : READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_synack_retries) + 1; + max_retries = min_t(int, max_retries, MAX_TCP_SYNACK_RETRIES); if (req->num_timeout >= max_retries) { tcp_write_err(sk); @@ -488,7 +489,7 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req) if (!tp->retrans_stamp) tp->retrans_stamp = tcp_time_stamp_ts(tp); tcp_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - req->timeout << req->num_timeout, false); + tcp_reqsk_timeout_sk(sk, req), false); } static bool tcp_rtx_probe0_timed_out(const struct sock *sk, -- 2.43.0