* [PATCH net v2 0/2] tcp/mptcp: prevent blackhole timeout arithmetic wraparound
@ 2026-11-14 16:12 Yingjie Wang
2026-11-14 16:12 ` [PATCH net v2 1/2] tcp: avoid wrapping Fast Open blackhole timeout Yingjie Wang
2026-11-14 16:12 ` [PATCH net v2 2/2] mptcp: avoid wrapping " Yingjie Wang
0 siblings, 2 replies; 3+ messages in thread
From: Yingjie Wang @ 2026-11-14 16:12 UTC (permalink / raw)
To: netdev
Cc: mptcp, linux-kernel, corbet, skhan, rdunlap, linux-doc, edumazet,
ncardwell, gang.yan, kuniyu, davem, kuba, pabeni, horms, matttbe,
martineau, geliang, ycheng, weiwan
The TCP Fast Open and MPTCP blackhole handlers multiply writable timeout
sysctl values before adding the result to a jiffies timestamp. The
multiplication is performed in 32-bit unsigned arithmetic, so a large
value can wrap into a short delay even on a 64-bit kernel.
With HZ=1000, a timeout of 6912213 seconds and the maximum multiplier of
64 should produce 442,381,632,000 jiffies, but the current calculations
truncate the result to 512 jiffies. Both patches compute the delay in u64
and cap it at MAX_JIFFY_OFFSET before adding it to the saved timestamp.
The issues were found using a static analysis tool. In the v1 arithmetic
A/B tests, loopback reproducers induced 12 blackholes, waited 1.2 seconds,
and then made a new connection:
TFO: base probe 1.026 s, TCPFastOpenActiveFail +1;
fixed probe 0.000 s, TCPFastOpenActiveFail +0.
MPTCP: base probe 3.087 s, MPCapableSYNTXDisabled +0;
fixed probe 0.000 s, MPCapableSYNTXDisabled +1.
The TFO counter records another failed active Fast Open attempt. The
MPTCP counter records a connection that skips MP_CAPABLE and falls back to
TCP while active MPTCP is disabled.
Changes since v1:
- Add a reasonable upper bound for the TCP Fast Open sysctl, as requested
by Kuniyuki Iwashima. This version proposes one day (86400 seconds),
using the existing IPv4 one_day_secs bound, and documents that limit.
Keep the existing MPTCP sysctl input range.
- Clarify that the multiplier is limited to 64 and the final delay is
separately capped for safe jiffies comparisons on 32-bit systems,
addressing Gang Yan's comment. Keep the READ_ONCE/WRITE_ONCE pairing
annotations next to the timestamp reads.
- Identify the original runtime results as v1 evidence in both commits.
- Retain Gang Yan's Reviewed-by tag on the unchanged MPTCP arithmetic fix.
v1: https://lore.kernel.org/r/cover.1794325665.git.x-professor@outlook.com
On the final v2 x86-64 HZ=1000 kernel, TCP accepts 86400 and rejects 86401;
MPTCP still accepts 86401 and INT_MAX. Boundary tests also cover zero,
negative and oversized values, failed-write preservation, defaults, and
network namespace isolation. The large timeout used in the v1 TFO test
is now rejected by the TCP sysctl limit.
The MPTCP blackhole test was rerun on this v2 kernel: all 12 clients
completed, and the probe used TCP fallback directly (0.000 s,
MPCapableSYNTXDisabled +1). The full x86-64 kernel build and affected
object builds on x86-64 and i386 passed. The upstream TCP and MPTCP
selftest suites were not run. Full allyesconfig/allmodconfig W=1 builds
stopped at warnings promoted to
errors in unchanged lockdep, coda, and x86 callthunks code;
the affected objects passed W=1 KCFLAGS=-Werror in both configurations.
The patches are independent and have separate Fixes tags.
Yingjie Wang (2):
tcp: avoid wrapping Fast Open blackhole timeout
mptcp: avoid wrapping blackhole timeout
Documentation/networking/ip-sysctl.rst | 1 +
net/ipv4/sysctl_net_ipv4.c | 1 +
net/ipv4/tcp_fastopen.c | 12 +++++++++---
net/mptcp/ctrl.c | 12 +++++++++---
4 files changed, 20 insertions(+), 6 deletions(-)
base-commit: 30c71476d842b094651bd7712f6c8ee8716147d0
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH net v2 1/2] tcp: avoid wrapping Fast Open blackhole timeout
2026-11-14 16:12 [PATCH net v2 0/2] tcp/mptcp: prevent blackhole timeout arithmetic wraparound Yingjie Wang
@ 2026-11-14 16:12 ` Yingjie Wang
2026-11-14 16:12 ` [PATCH net v2 2/2] mptcp: avoid wrapping " Yingjie Wang
1 sibling, 0 replies; 3+ messages in thread
From: Yingjie Wang @ 2026-11-14 16:12 UTC (permalink / raw)
To: netdev
Cc: mptcp, linux-kernel, corbet, skhan, rdunlap, linux-doc, edumazet,
ncardwell, gang.yan, kuniyu, davem, kuba, pabeni, horms, matttbe,
martineau, geliang, ycheng, weiwan, stable
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@vger.kernel.org
Signed-off-by: Yingjie Wang <x-professor@outlook.com>
---
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
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH net v2 2/2] mptcp: avoid wrapping blackhole timeout
2026-11-14 16:12 [PATCH net v2 0/2] tcp/mptcp: prevent blackhole timeout arithmetic wraparound Yingjie Wang
2026-11-14 16:12 ` [PATCH net v2 1/2] tcp: avoid wrapping Fast Open blackhole timeout Yingjie Wang
@ 2026-11-14 16:12 ` Yingjie Wang
1 sibling, 0 replies; 3+ messages in thread
From: Yingjie Wang @ 2026-11-14 16:12 UTC (permalink / raw)
To: netdev
Cc: mptcp, linux-kernel, corbet, skhan, rdunlap, linux-doc, edumazet,
ncardwell, gang.yan, kuniyu, davem, kuba, pabeni, horms, matttbe,
martineau, geliang, ycheng, weiwan, stable, Gang Yan
mptcp_active_should_disable() calculates the active-disable interval as
multiplier * blackhole_timeout * HZ. Since all operands are 32-bit, a
large blackhole_timeout can wrap the delay even on 64-bit kernels and
make active MPTCP available again while the blackhole is still present.
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 MPTCP blackholes and waited 1.2 seconds before opening another
connection. In the v1 arithmetic-only test, the unpatched kernel retried
MP_CAPABLE, while the fixed kernel used TCP fallback directly. 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. The multiplier remains limited to 64, while
the separate cap keeps the delay within the safe jiffies comparison range
on 32-bit systems. Preserve the existing sysctl input range and backoff
for representable intervals.
On the v2 kernel, the loopback blackhole reproducer completed all 12
clients and the probe used TCP fallback directly instead of retrying
MP_CAPABLE.
Fixes: 27069e7cb3d1 ("mptcp: disable active MPTCP in case of blackhole")
Cc: stable@vger.kernel.org
Reviewed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Yingjie Wang <x-professor@outlook.com>
---
net/mptcp/ctrl.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c
index 63c5747f0f63..0b10e94e7f43 100644
--- a/net/mptcp/ctrl.c
+++ b/net/mptcp/ctrl.c
@@ -487,6 +487,7 @@ bool mptcp_active_should_disable(struct sock *ssk)
unsigned long timeout;
int disable_times;
int multiplier;
+ u64 delay;
pernet = mptcp_get_pernet(net);
blackhole_timeout = READ_ONCE(pernet->blackhole_timeout);
@@ -501,12 +502,17 @@ bool mptcp_active_should_disable(struct sock *ssk)
/* Paired with smp_mb__before_atomic() in mptcp_active_disable() */
smp_rmb();
- /* Limit timeout to max: 2^6 * initial timeout */
+ /* Limit the backoff multiplier to 64. */
multiplier = 1 << min(disable_times - 1, 6);
+ delay = (u64)multiplier * blackhole_timeout * HZ;
- /* Paired with the WRITE_ONCE() in mptcp_active_disable(). */
+ /*
+ * Cap the delay for safe jiffies comparisons on 32-bit systems.
+ * The timestamp read is paired with WRITE_ONCE() in
+ * mptcp_active_disable().
+ */
timeout = READ_ONCE(pernet->active_disable_stamp) +
- multiplier * blackhole_timeout * HZ;
+ min(delay, MAX_JIFFY_OFFSET);
return time_before(jiffies, timeout);
}
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-14 16:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-14 16:12 [PATCH net v2 0/2] tcp/mptcp: prevent blackhole timeout arithmetic wraparound Yingjie Wang
2026-11-14 16:12 ` [PATCH net v2 1/2] tcp: avoid wrapping Fast Open blackhole timeout Yingjie Wang
2026-11-14 16:12 ` [PATCH net v2 2/2] mptcp: avoid wrapping " Yingjie Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®