Re: [PATCH net v7 1/1] tcp: bound SYN-ACK timers to reqsk timeout range
From: Eric Dumazet <edumazet@google.com>
Date: 2026-09-03 06:37:34
Also in:
linux-doc
On Thu, Sep 3, 2026 at 8:18 AM Zhiling Zou [off-list ref] wrote:
quoted hunk ↗ jump to hunk
request_sock::num_timeout is a 7-bit counter. Commit e6c022a4fa2d ("tcp: better retrans tracking for defer-accept") split this counter out of an 8-bit field, but tcp_synack_retries still accepts an 8-bit value and TCP_DEFER_ACCEPT can still derive a retry count up to 255. If these settings exceed 127, the regular request timer cannot reach its expiration threshold and num_timeout wraps to zero. After the wrap, the request can keep timing out instead of expiring, and the next zero-to-one transition repeats the young-queue accounting decrement. Both request timer paths can also shift req->timeout by 64 or more while calculating the next RTO. UBSAN reports that invalid shift, and systems with panic_on_warn=1 panic before the later cap can take effect. Keep the tcp_synack_retries sysctl range unchanged, but cap its effective value in both SYN-ACK timer paths before the young-queue pruning loop. Cap the TCP_DEFER_ACCEPT conversion at the same range so its timer and bare-ACK consumers agree. Saturate the RTO calculation before shifting, and cap the Fast Open extra retry as well. Snapshot the request timeout and num_timeout once before the bounds check and shift. num_timeout is a bitfield, so add a raw view of its existing storage byte for a compile-safe READ_ONCE() snapshot. This keeps the check and shift consistent when the timer concurrently increments num_timeout. Document that the sysctl still accepts 0-255 and that the timers silently cap the effective retry count at 127. Fixes: e6c022a4fa2d ("tcp: better retrans tracking for defer-accept") Cc: stable@vger.kernel.org Reported-by: Vega <redacted> Signed-off-by: Zhiling Zou <redacted> --- changes in v7: Documentation/networking/ip-sysctl.rst | 4 +++- include/net/request_sock.h | 20 ++++++++++++++++++-- include/net/tcp.h | 21 +++++++++++++++++---- net/ipv4/inet_connection_sock.c | 2 ++ net/ipv4/tcp.c | 2 +- net/ipv4/tcp_timer.c | 6 ++++-- 6 files changed, 45 insertions(+), 10 deletions(-)diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 208f46967ee59..4a2ed964dceab 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst@@ -954,7 +954,9 @@ tcp_stdurg - BOOLEAN tcp_synack_retries - INTEGER Number of times SYNACKs for a passive TCP connection attempt will - be retransmitted. Should not be higher than 255. Default value + be retransmitted. The sysctl accepts 0-255. Values above 127 are + silently capped by the SYN-ACK timers, matching the 7-bit + request_sock::num_timeout field. Default value is 5, which corresponds to 31seconds till the last retransmission with the current initial RTO of 1second. With this the final timeout for a passive TCP connection will happen after 63seconds.diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 5a9c826a7092d..a9781fab774aa 100644 --- a/include/net/request_sock.h +++ b/include/nets/request_sock.h@@ -58,12 +58,17 @@ struct request_sock { struct request_sock *dl_next; u16 mss; u8 num_retrans; /* number of retransmits */ - u8 syncookie:1; /* True if + union { + struct { + u8 syncookie:1; /* True if * 1) tcpopts needs to be encoded in * TS of SYN+ACK * 2) ACK is validated by BPF kfunc. */ - u8 num_timeout:7; /* number of timeouts */ + u8 num_timeout:7; /* number of timeouts */ + }; + u8 num_timeout_syncookie; + }; u32 ts_recent; struct timer_list rsk_timer; const struct request_sock_ops *rsk_ops;@@ -74,6 +79,17 @@ struct request_sock { u32 timeout; }; +static inline u8 reqsk_num_timeout(const struct request_sock *req) +{ + u8 num_timeout = READ_ONCE(req->num_timeout_syncookie); + +#if defined(__LITTLE_ENDIAN_BITFIELD) + return num_timeout >> 1; +#else + return num_timeout & 0x7f; +#endif +} +
Please drop all the changes to include/net/request_sock.h
Instead, you can simply bound the shift amount in tcp_reqsk_timeout_sk():
static inline unsigned long tcp_reqsk_timeout_sk(const struct sock *sk,
const struct request_sock *req)
{
u64 timeout = (u64)READ_ONCE(req->timeout) << min_t(u8,
req->num_timeout, 30);
return (unsigned long)min_t(u64, timeout, tcp_rto_max(sk));
}
Thanks.