[PATCH net 1/2] tcp: avoid wrapping Fast Open blackhole timeout

From: Yingjie Wang

Date: Tue Nov 10 2026 - 10:59:14 EST


tcp_fastopen_active_should_disable() calculates the active-disable
interval as multiplier * tfo_bh_timeout * HZ. Since all operands are
32-bit, a large tcp_fastopen_blackhole_timeout_sec can wrap the delay
even on 64-bit kernels and re-enable active Fast Open too soon.

For example, with HZ=1000, a timeout of 6912213 seconds and the maximum
multiplier of 64 should produce 442381632000 jiffies, but the current
calculation truncates it to 512 jiffies.

This issue was found using a static analysis tool. A loopback reproducer
induced 12 Fast Open blackholes and waited 1.2 seconds before opening
another connection. The unpatched kernel retried active Fast Open, while
the patched kernel kept Fast Open disabled and used a regular TCP
handshake. The reproducer required neither kernel modifications nor
fault injection.

Compute the interval in u64 and cap it at MAX_JIFFY_OFFSET before adding
it to the saved timestamp. This preserves the existing exponential
backoff for representable intervals and prevents large values from
wrapping into short timeouts.

Fixes: cf1ef3f0719b ("net/tcp_fastopen: Disable active side TFO in certain scenarios")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yingjie Wang <x-professor@xxxxxxxxxxx>
---
net/ipv4/tcp_fastopen.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
index 7f7eb3cc1c04..aeefd605414f 100644
--- a/net/ipv4/tcp_fastopen.c
+++ b/net/ipv4/tcp_fastopen.c
@@ -613,6 +613,7 @@ bool tcp_fastopen_active_should_disable(struct sock *sk)
unsigned long timeout;
int tfo_da_times;
int multiplier;
+ u64 delay;

if (!tfo_bh_timeout)
return false;
@@ -626,10 +627,11 @@ bool tcp_fastopen_active_should_disable(struct sock *sk)

/* Limit timeout to max: 2^6 * initial timeout */
multiplier = 1 << min(tfo_da_times - 1, 6);
+ delay = (u64)multiplier * tfo_bh_timeout * HZ;

/* Paired with the WRITE_ONCE() in tcp_fastopen_active_disable(). */
timeout = READ_ONCE(sock_net(sk)->ipv4.tfo_active_disable_stamp) +
- multiplier * tfo_bh_timeout * HZ;
+ min(delay, MAX_JIFFY_OFFSET);
if (time_before(jiffies, timeout))
return true;

--
2.43.0