Thread (3 messages) flat view 3 messages, 2 authors, 5d ago

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.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help