Skip to contentSkip to conversation

tcp: clamp route advmss to TCP_MIN_MSS

PATCH Applied Ren Wei 2 participants 3 messages Aug 19 – Aug 22

Subsystems (3)
lore
Share & tools
lore

Ren Wei

author
#0 lore raw

v2 cover tcp: clamp route advmss to TCP_MIN_MSS

From: Yong Wang <[email protected]>

Hi Linux kernel maintainers,

This is v2 of the fix for the divide-by-zero reachable from tcp_select_initial_window() via undersized route-derived advmss.

The previous version only rejected undersized non-zero RTAX_ADVMSS values at the route metric input point. As pointed out in review, that does not fully fix the bug because the panic is still reachable through the "default advmss" path when RTAX_ADVMSS is 0 and the effective advmss is later driven down by route MTU and min_adv_mss.

This version fixes the bug in TCP by introducing a helper that clamps route-derived advmss to TCP_MIN_MSS before it is consumed by the TCP paths that derive advmss from dst metrics.

I tested this version in QEMU and confirmed that the previously reproducible divide-by-zero no longer occurs on the advmss=0 + small-MTU/min_adv_mss path.

Thanks,
Yong Wang

---
Changes in v2:
- drop the RTAX_ADVMSS input validation from previous version
- clamp route-derived advmss in TCP instead
- switch the relevant TCP IPv4/IPv6 call sites to the new helper
- drop the long reproducer script and crash log from the cover letter
v1 link: https://lore.kernel.org/all/2c3901162c65a1d85cc1756a83a458db834d70c1.1786610865.git.edragain@163.com/

Yong Wang (1):
tcp: clamp route advmss to TCP_MIN_MSS

 include/net/tcp.h        | 5 +++++
 net/ipv4/tcp_ipv4.c      | 2 +-
 net/ipv4/tcp_minisocks.c | 2 +-
 net/ipv4/tcp_output.c    | 6 +++---
 net/ipv6/tcp_ipv6.c      | 2 +-
 5 files changed, 11 insertions(+), 6 deletions(-)
Signature · 1 line
2.53.0
author
#1 lore raw

PATCH v2 1/1 tcp: clamp route advmss to TCP_MIN_MSS

From: Yong Wang <[email protected]>

tcp_select_initial_window() assumes that callers never pass an MSS smaller than 1, but route-derived advmss values can violate that assumption.

A too-small explicit RTAX_ADVMSS is one way to get there, but it is not the only one. The same divide-by-zero can also be reached through the "default advmss" path when RTAX_ADVMSS is left at 0 and the effective advmss is later driven down by route MTU and min_adv_mss.

Introduce a tcp_dst_advmss() helper that clamps route advmss to TCP_MIN_MSS before TCP consumes it, and use it in the TCP paths that derive advmss from dst metrics. This keeps the effective MSS from dropping to zero before tcp_select_initial_window() rounds the receive window.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by Codex:GPT-5.4
---
 include/net/tcp.h        | 5 +++++
 net/ipv4/tcp_ipv4.c      | 2 +-
 net/ipv4/tcp_minisocks.c | 2 +-
 net/ipv4/tcp_output.c    | 6 +++---
 net/ipv6/tcp_ipv6.c      | 2 +-
 5 files changed, 11 insertions(+), 6 deletions(-)
include/net/tcp.h +5 -0
index 2c5b889530b5..670c20876f26 100644
@@ -1782,6 +1782,11 @@ static inline int tcp_full_space(const struct sock *sk)
 	return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf));
 }
 
+static inline u32 tcp_dst_advmss(const struct dst_entry *dst)
+{
+	return max_t(u32, dst_metric_advmss(dst), TCP_MIN_MSS);
+}
+
 static inline void __tcp_adjust_rcv_ssthresh(struct sock *sk, u32 new_ssthresh)
 {
 	int unused_mem = sk_unused_reserved_mem(sk);
net/ipv4/tcp_ipv4.c +1 -1
index 7f413f509d7d..497b1a0370cd 100644
@@ -1736,7 +1736,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
 	tcp_ca_openreq_child(newsk, dst);
 
 	tcp_sync_mss(newsk, dst4_mtu(dst));
-	newtp->advmss = tcp_mss_clamp(tcp_sk(sk), dst_metric_advmss(dst));
+	newtp->advmss = tcp_mss_clamp(tcp_sk(sk), tcp_dst_advmss(dst));
 
 	tcp_initialize_rcv_mss(newsk);
 
net/ipv4/tcp_minisocks.c +1 -1
index 6ab3e3a0b431..fb901b368ecc 100644
@@ -440,7 +440,7 @@ void tcp_openreq_init_rwin(struct request_sock *req,
 	u32 rcv_wnd;
 	int mss;
 
-	mss = tcp_mss_clamp(tp, dst_metric_advmss(dst));
+	mss = tcp_mss_clamp(tp, tcp_dst_advmss(dst));
 	window_clamp = READ_ONCE(tp->window_clamp);
 	/* Set this up on the first call only */
 	req->rsk_window_clamp = window_clamp ? : dst_metric(dst, RTAX_WINDOW);
net/ipv4/tcp_output.c +3 -3
index d7c1444b5e30..7b761edf86ee 100644
@@ -143,7 +143,7 @@ static __u16 tcp_advertise_mss(struct sock *sk)
 	int mss = tp->advmss;
 
 	if (dst) {
-		unsigned int metric = dst_metric_advmss(dst);
+		unsigned int metric = tcp_dst_advmss(dst);
 
 		if (metric < mss) {
 			mss = metric;
@@ -3972,7 +3972,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
 	}
 	skb_dst_set(skb, dst);
 
-	mss = tcp_mss_clamp(tp, dst_metric_advmss(dst));
+	mss = tcp_mss_clamp(tp, tcp_dst_advmss(dst));
 
 	memset(&opts, 0, sizeof(opts));
 	now = tcp_clock_ns();
@@ -4127,7 +4127,7 @@ static void tcp_connect_init(struct sock *sk)
 
 	if (!tp->window_clamp)
 		WRITE_ONCE(tp->window_clamp, dst_metric(dst, RTAX_WINDOW));
-	tp->advmss = tcp_mss_clamp(tp, dst_metric_advmss(dst));
+	tp->advmss = tcp_mss_clamp(tp, tcp_dst_advmss(dst));
 
 	tcp_initialize_rcv_mss(sk);
 
net/ipv6/tcp_ipv6.c +1 -1
index 9e9155b1b3aa..df9c29eb5c1f 100644
@@ -1487,7 +1487,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
 	tcp_ca_openreq_child(newsk, dst);
 
 	tcp_sync_mss(newsk, dst6_mtu(dst));
-	newtp->advmss = tcp_mss_clamp(tcp_sk(sk), dst_metric_advmss(dst));
+	newtp->advmss = tcp_mss_clamp(tcp_sk(sk), tcp_dst_advmss(dst));
 
 	tcp_initialize_rcv_mss(newsk);
 
Signature · 1 line
2.53.0
#2 lore raw
In reply to Ren Wei
This patch was applied to netdev/net.git (main) by Jakub Kicinski <[email protected]>:

Hello:

This patch was applied to netdev/net.git (main)
by Jakub Kicinski <[email protected]>:

Quoted 8 lines · On Wed, 19 Aug 2026 23:22:03 +0800 you wrote:

From: Yong Wang <[email protected]>

Hi Linux kernel maintainers,

This is v2 of the fix for the divide-by-zero reachable from tcp_select_initial_window() via undersized route-derived advmss.

[...]

Here is the summary with links:
- [net,v2,1/1] tcp: clamp route advmss to TCP_MIN_MSS

    https://git.kernel.org/netdev/net/c/870a9e42ecc6

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html