[PATCH net v2 1/2] tcp: avoid wrapping Fast Open blackhole timeout
From: Yingjie Wang
Date: Sat Nov 14 2026 - 11:15:06 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 442,381,632,000 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. In the v1 arithmetic-only test, the unpatched kernel
retried active Fast Open, while the fixed kernel used a regular TCP
handshake. The reproducer required neither kernel modifications nor
fault injection. The input limit added here rejects that large setting.
Compute the interval in u64 and cap it at MAX_JIFFY_OFFSET before adding
it to the saved timestamp. Also limit the writable initial timeout to one
day, so the exponential backoff does not start from an impractically long
period. Even at this limit, a 64-fold backoff with HZ=1000 exceeds the
32-bit range, so the wider calculation and jiffies cap are still needed.
On the v2 kernel, the sysctl accepts 86400 seconds and rejects 86401,
leaving the previous value unchanged.
Fixes: cf1ef3f0719b ("net/tcp_fastopen: Disable active side TFO in certain scenarios")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yingjie Wang <x-professor@xxxxxxxxxxx>
---
Documentation/networking/ip-sysctl.rst | 1 +
net/ipv4/sysctl_net_ipv4.c | 1 +
net/ipv4/tcp_fastopen.c | 12 +++++++++---
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index d3523c9064a2..d1e66feb0153 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -1055,6 +1055,7 @@ tcp_fastopen_blackhole_timeout_sec - INTEGER
get detected right after Fastopen is re-enabled and will reset to
initial value when the blackhole issue goes away.
0 to disable the blackhole detection.
+ The maximum value is one day (86400 seconds).
By default, it is set to 0 (feature is disabled).
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index bf193e7ec516..5bc357e189bd 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1152,6 +1152,7 @@ static const struct ctl_table ipv4_net_table[] = {
.mode = 0644,
.proc_handler = proc_tfo_blackhole_detect_timeout,
.extra1 = SYSCTL_ZERO,
+ .extra2 = &one_day_secs,
},
#ifdef CONFIG_IP_ROUTE_MULTIPATH
{
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
index 7f7eb3cc1c04..883f0f1e7e07 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;
@@ -624,12 +625,17 @@ bool tcp_fastopen_active_should_disable(struct sock *sk)
/* Paired with smp_mb__before_atomic() in tcp_fastopen_active_disable() */
smp_rmb();
- /* Limit timeout to max: 2^6 * initial timeout */
+ /* Limit the backoff multiplier to 64. */
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(). */
+ /*
+ * Cap the delay for safe jiffies comparisons on 32-bit systems.
+ * The timestamp read is paired with 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