FAILED: patch "[PATCH] tcp: clamp route advmss to TCP_MIN_MSS" failed to apply to 6.6-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026083105-buddhist-verdict-4f97@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1 Mon Sep 17 00:00:00 2001
From: Yong Wang <[email protected]>
Date: Wed, 19 Aug 2026 23:22:04 +0800
Subject: [PATCH] tcp: clamp route advmss to TCP_MIN_MSS
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.
include/net/tcp.h +5 -0
@@ -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
@@ -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
@@ -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
@@ -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 ();
@@ -4128,7 +4128,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
@@ -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);
Sasha Levin
maintainerPATCH 1/5 ipv6: pass proto by value to ipv6_push_nfrag_opts() and ipv6_push_frag_opts()
From: Eric Dumazet <[email protected]>
[ Upstream commit 1bc46dd209667346c5aa56c351995e7c260696d0 ]
With CONFIG_STACKPROTECTOR_STRONG=y, it is better to avoid passing a pointer to an automatic variable.
Change these exported functions to return 'u8 proto' instead of void.
- ipv6_push_nfrag_opts()
- ipv6_push_frag_opts()
For instance, replace
ipv6_push_frag_opts(skb, opt, &proto); with: proto = ipv6_push_frag_opts(skb, opt, proto);
Note that even after this change, ip6_xmit() has to use a stack canary because of @first_hop variable.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- include/net/ipv6.h | 10 ++++---- net/ipv6/exthdrs.c | 55 +++++++++++++++++++++++-------------------- net/ipv6/ip6_output.c | 19 ++++++++------- net/ipv6/ip6_tunnel.c | 2 +- 4 files changed, 46 insertions(+), 40 deletions(-)
include/net/ipv6.h +5 -5
@@ -1154,11 +1154,11 @@ int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);* Extension header (options) processing */ -void ipv6_push_nfrag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, -u8 *proto,struct in6_addr **daddr_p, -struct in6_addr *saddr); -void ipv6_push_frag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, -u8 *proto); +u8 ipv6_push_nfrag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, +u8 proto,struct in6_addr **daddr_p, +struct in6_addr *saddr); +u8 ipv6_push_frag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, +u8 proto);int ipv6_skip_exthdr (const struct sk_buff *,int start,u8 *nexthdrp,__be16 *frag_offp);
net/ipv6/exthdrs.c +29 -26
109 lines not on this page · raw message
net/ipv6/ip6_output.c +11 -8
@@ -299,11 +299,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, seg_len += opt->opt_nflen + opt->opt_flen;if (opt->opt_flen) -ipv6_push_frag_opts (skb, opt, &proto); + proto =ipv6_push_frag_opts (skb, opt, proto);if (opt->opt_nflen) -ipv6_push_nfrag_opts (skb, opt, &proto, &first_hop, - &fl6->saddr); + proto =ipv6_push_nfrag_opts (skb, opt, proto, + &first_hop, + &fl6->saddr); }if (unlikely (seg_len >IPV6_MAXPLEN )) {
@@ -1930,11 +1931,13 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,__skb_pull (skb,skb_network_header_len (skb)); final_dst = &fl6->daddr; -if (opt && opt->opt_flen) -ipv6_push_frag_opts (skb, opt, &proto); -if (opt && opt->opt_nflen) -ipv6_push_nfrag_opts (skb, opt, &proto, &final_dst, &fl6->saddr); - +if (opt) { +if (opt->opt_flen) + proto =ipv6_push_frag_opts (skb, opt, proto); +if (opt->opt_nflen) + proto =ipv6_push_nfrag_opts (skb, opt, proto, + &final_dst, &fl6->saddr); + }skb_push (skb,sizeof (struct ipv6hdr ));skb_reset_network_header (skb); hdr =ipv6_hdr (skb);
net/ipv6/ip6_tunnel.c +1 -1
@@ -1271,7 +1271,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,if (encap_limit >=0 ) {init_tel_txopt (&opt, encap_limit); -ipv6_push_frag_opts (skb, &opt.ops, &proto); + proto =ipv6_push_frag_opts (skb, &opt.ops, proto); }skb_push (skb,sizeof (struct ipv6hdr ));
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 inet: add dst4_mtu() and dst6_mtu() helpers
From: Eric Dumazet <[email protected]>
[ Upstream commit 8776c4ef3ab22b95f55713f00a7a576e6402507d ]
With CONFIG_MITIGATION_RETPOLINE=y dst_mtu() is a bit fat, because it is generic.
Indeed, clang does not always inline it.
Add dst4_mtu() and dst6_mtu() helpers for callers that expect either ipv4_mtu() or ip6_mtu() to be called.
These helpers are always inlined.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- include/net/dst.h | 6 ++++++ include/net/ip6_route.h | 6 ++++++ 2 files changed, 12 insertions(+)
include/net/dst.h +6 -0
@@ -216,6 +216,12 @@ static inline u32 dst_mtu(const struct dst_entry *dst)return INDIRECT_CALL_INET (dst->ops->mtu, ip6_mtu, ipv4_mtu, dst); } +/* Variant of dst_mtu() for IPv4 users. */ +static inline u32 dst4_mtu (const struct dst_entry *dst) +{ +return INDIRECT_CALL_1 (dst->ops->mtu, ipv4_mtu, dst); +} +/* RTT metrics are stored in milliseconds for user ABI, but used as jiffies */ static inline unsigned long dst_metric_rtt (const struct dst_entry *dst,int metric) {
include/net/ip6_route.h +6 -0
@@ -266,6 +266,12 @@ static inline bool ipv6_anycast_destination(const struct dst_entry *dst,int ip6_fragment (struct net *net,struct sock *sk,struct sk_buff *skb,int (*output)(struct net *,struct sock *,struct sk_buff *)); +/* Variant of dst_mtu() for IPv6 users */ +static inline u32 dst6_mtu (const struct dst_entry *dst) +{ +return INDIRECT_CALL_1 (dst->ops->mtu, ip6_mtu, dst); +} +static inline unsigned int ip6_skb_dst_mtu (const struct sk_buff *skb) { const struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 ipv6: use dst6_mtu() instead of dst_mtu()
In reply to Sasha LevinFrom: Eric Dumazet <[email protected]>
[ Upstream commit b40f0130a23b6bab8b359e158a40af81f11f14be ]
When we expect an IPv6 dst, use dst6_mtu() instead of dst_mtu() to save some code space.
Due to current dst6_mtu() implementation, only convert users in IPv6 stack.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- net/ipv6/ip6_gre.c | 3 ++- net/ipv6/ip6_output.c | 6 +++--- net/ipv6/ip6_tunnel.c | 4 ++-- net/ipv6/ipv6_sockglue.c | 4 ++-- net/ipv6/route.c | 10 ++++++---- net/ipv6/tcp_ipv6.c | 9 +++++---- 6 files changed, 20 insertions(+), 16 deletions(-)
net/ipv6/ip6_gre.c +2 -1
@@ -1071,9 +1071,10 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,gre_build_header (skb,8 ,TUNNEL_SEQ , proto,0 ,htonl (atomic_fetch_inc (&t->o_seqno)));/* TooBig packet may have updated dst->dev's mtu */ -if (!t->parms.collect_md && dst &&dst_mtu (dst) > dst->dev->mtu) +if (!t->parms.collect_md && dst &&dst6_mtu (dst) > dst->dev->mtu) dst->ops->update_pmtu (dst,NULL , skb, dst->dev->mtu, false); + err =ip6_tnl_xmit (skb, dev, dsfield, &fl6, encap_limit, &mtu,NEXTHDR_GRE );if (err !=0 ) {
net/ipv6/ip6_output.c +3 -3
@@ -347,7 +347,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, skb->priority = priority; skb->mark = mark; - mtu =dst_mtu (dst); + mtu =dst6_mtu (dst);if ((skb->len <= mtu) || skb->ignore_df ||skb_is_gso (skb)) {IP6_INC_STATS (net, idev,IPSTATS_MIB_OUTREQUESTS );
@@ -1396,10 +1396,10 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, v6_cork->tclass = ipc6->tclass;if (rt->dst.flags &DST_XFRM_TUNNEL ) mtu = np->pmtudisc >=IPV6_PMTUDISC_PROBE ? -READ_ONCE (rt->dst.dev->mtu) :dst_mtu (&rt->dst); +READ_ONCE (rt->dst.dev->mtu) :dst6_mtu (&rt->dst);else mtu = np->pmtudisc >=IPV6_PMTUDISC_PROBE ? -READ_ONCE (rt->dst.dev->mtu) :dst_mtu (xfrm_dst_path (&rt->dst)); +READ_ONCE (rt->dst.dev->mtu) :dst6_mtu (xfrm_dst_path (&rt->dst));if (np->frag_size < mtu) {if (np->frag_size) mtu = np->frag_size;
net/ipv6/ip6_tunnel.c +2 -2
@@ -641,7 +641,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,/* change mtu on this route */ if (rel_type ==ICMP_DEST_UNREACH && rel_code ==ICMP_FRAG_NEEDED ) { -if (rel_info >dst_mtu (skb_dst (skb2))) +if (rel_info >dst6_mtu (skb_dst (skb2))) goto out;skb_dst_update_pmtu_no_confirm (skb2, rel_info);
@@ -1193,7 +1193,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, t->parms.name); goto tx_err_dst_release; } - mtu =dst_mtu (dst) - eth_hlen - psh_hlen - t->tun_hlen; + mtu =dst6_mtu (dst) - eth_hlen - psh_hlen - t->tun_hlen;if (encap_limit >=0 ) { max_headroom +=8 ; mtu -=8 ;
net/ipv6/ipv6_sockglue.c +2 -2
@@ -1216,7 +1216,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,rcu_read_lock (); dst =__sk_dst_get (sk);if (dst) - val =dst_mtu (dst); + val =dst6_mtu (dst);rcu_read_unlock ();if (!val)return -ENOTCONN ;
@@ -1315,7 +1315,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,rcu_read_lock (); dst =__sk_dst_get (sk);if (dst) - mtuinfo.ip6m_mtu =dst_mtu (dst); + mtuinfo.ip6m_mtu =dst6_mtu (dst);rcu_read_unlock ();if (!mtuinfo.ip6m_mtu)return -ENOTCONN ;
net/ipv6/route.c +6 -4
@@ -2041,6 +2041,8 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)static bool rt6_mtu_change_route_allowed (struct inet6_dev *idev,struct rt6_info *rt,int mtu) { +u32 dmtu =dst6_mtu (&rt->dst); +/* If the new MTU is lower than the route PMTU, this new MTU will be the * lowest MTU in the path: always allow updating the route PMTU to * reflect PMTU decreases.
@@ -2051,10 +2053,10 @@ static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,* handle this. */ -if (dst_mtu (&rt->dst) >= mtu) +if (dmtu >= mtu)return true; -if (dst_mtu (&rt->dst) == idev->cnf.mtu6) +if (dmtu == idev->cnf.mtu6)return true;return false;
@@ -2917,7 +2919,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,if (mtu <IPV6_MIN_MTU )return ; -if (mtu >=dst_mtu (dst)) +if (mtu >=dst6_mtu (dst))return ;if (!rt6_cache_allowed_for_pmtu (rt6)) {
@@ -3235,7 +3237,7 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect);static unsigned int ip6_default_advmss (const struct dst_entry *dst) {struct net_device *dev = dst->dev; -unsigned int mtu =dst_mtu (dst); +unsigned int mtu =dst6_mtu (dst);struct net *net; mtu -=sizeof (struct ipv6hdr ) +sizeof (struct tcphdr );
net/ipv6/tcp_ipv6.c +5 -4
@@ -352,7 +352,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,static void tcp_v6_mtu_reduced (struct sock *sk) {struct dst_entry *dst; -u32 mtu; +u32 mtu, dmtu;if ((1 << sk->sk_state) & (TCPF_LISTEN |TCPF_CLOSE ))return ;
@@ -369,8 +369,9 @@ static void tcp_v6_mtu_reduced(struct sock *sk)if (!dst)return ; -if (inet_csk (sk)->icsk_pmtu_cookie >dst_mtu (dst)) { -tcp_sync_mss (sk,dst_mtu (dst)); + dmtu =dst6_mtu (dst); +if (inet_csk (sk)->icsk_pmtu_cookie > dmtu) { +tcp_sync_mss (sk, dmtu);tcp_simple_retransmit (sk); } }
@@ -1339,7 +1340,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,dst_mtu (dst)); +tcp_sync_mss (newsk,dst6_mtu (dst)); newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst));tcp_initialize_rcv_mss (newsk);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 ipv4: use dst4_mtu() instead of dst_mtu()
In reply to Sasha LevinFrom: Eric Dumazet <[email protected]>
[ Upstream commit fe8570186f100b6cc499b2f7705946baf1388cde ]
When we expect an IPv4 dst, use dst4_mtu() instead of dst_mtu() to save some code space.
[ Resolved conflicts in net/ipv4/ip_output.c and net/ipv4/ipmr.c,
caused by unrelated local/upstream divergence unrelated to this commit's own diff:
- ip_output.c: upstream's pre-image already has
'pmtudisc = READ_ONCE(inet->pmtudisc);' hoisted out of the if
condition in __ip_make_skb() (from a commit not present in this
tree); kept this tree's un-hoisted 'inet->pmtudisc' form and
applied only the dst_mtu() -> dst4_mtu() substitution. - ipmr.c: this tree already has an extra 'dev = rt->dst.dev;' line before the MTU check in ipmr_prepare_xmit() that upstream's pre-image doesn't carry; kept that line and applied only the dst_mtu() -> dst4_mtu() substitution. ]
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- net/ipv4/icmp.c | 2 +- net/ipv4/ip_output.c | 4 ++-- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/netfilter/nf_reject_ipv4.c | 2 +- net/ipv4/tcp_ipv4.c | 13 ++++++------- net/ipv6/sit.c | 2 +- 7 files changed, 13 insertions(+), 14 deletions(-)
net/ipv4/icmp.c +1 -1
@@ -785,7 +785,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,/* RFC says return as much as we can without exceeding 576 bytes. */ - room =dst_mtu (&rt->dst); + room =dst4_mtu (&rt->dst);if (room >576 ) room =576 ; room -=sizeof (struct iphdr ) + icmp_param.replyopts.opt.opt.optlen;
net/ipv4/ip_output.c +2 -2
@@ -1304,7 +1304,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,return -EFAULT ; cork->fragsize =ip_sk_use_pmtu (sk) ? -dst_mtu (&rt->dst) :READ_ONCE (rt->dst.dev->mtu); +dst4_mtu (&rt->dst) :READ_ONCE (rt->dst.dev->mtu);if (!inetdev_valid_mtu (cork->fragsize))return -ENETUNREACH ;
@@ -1438,7 +1438,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,* locally. */ if (inet->pmtudisc ==IP_PMTUDISC_DO || inet->pmtudisc ==IP_PMTUDISC_PROBE || - (skb->len <=dst_mtu (&rt->dst) && + (skb->len <=dst4_mtu (&rt->dst) &&ip_dont_fragment (sk, &rt->dst))) df =htons (IP_DF );
net/ipv4/ip_sockglue.c +1 -1
@@ -1642,7 +1642,7 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, val =0 ; dst =sk_dst_get (sk);if (dst) { - val =dst_mtu (dst); + val =dst4_mtu (dst);dst_release (dst); }if (!val) {
net/ipv4/ipmr.c +1 -1
@@ -1895,7 +1895,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, dev = rt->dst.dev; -if (skb->len+encap >dst_mtu (&rt->dst) && (ntohs (iph->frag_off) &IP_DF )) { +if (skb->len+encap >dst4_mtu (&rt->dst) && (ntohs (iph->frag_off) &IP_DF )) {/* Do not fragment multicasts. Alas, IPv4 does not * allow to send ICMP, so that packets will disappear * to blackhole.
net/ipv4/netfilter/nf_reject_ipv4.c +1 -1
@@ -296,7 +296,7 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb, goto free_nskb;/* "Never happens" */ -if (nskb->len >dst_mtu (skb_dst (nskb))) +if (nskb->len >dst4_mtu (skb_dst (nskb))) goto free_nskb;nf_ct_attach (nskb, oldskb);
net/ipv4/tcp_ipv4.c +6 -7
@@ -363,7 +363,7 @@ void tcp_v4_mtu_reduced(struct sock *sk) {struct inet_sock *inet =inet_sk (sk);struct dst_entry *dst; -u32 mtu; +u32 mtu, dmtu;if ((1 << sk->sk_state) & (TCPF_LISTEN |TCPF_CLOSE ))return ;
@@ -375,15 +375,14 @@ void tcp_v4_mtu_reduced(struct sock *sk)/* Something is about to be wrong... Remember soft error * for the case, if this connection will not able to recover. */ -if (mtu <dst_mtu (dst) &&ip_dont_fragment (sk, dst)) + dmtu =dst4_mtu (dst); +if (mtu < dmtu &&ip_dont_fragment (sk, dst))WRITE_ONCE (sk->sk_err_soft,EMSGSIZE ); - mtu =dst_mtu (dst); -if (inet->pmtudisc !=IP_PMTUDISC_DONT &&ip_sk_accept_pmtu (sk) && -inet_csk (sk)->icsk_pmtu_cookie > mtu) { -tcp_sync_mss (sk, mtu); +inet_csk (sk)->icsk_pmtu_cookie > dmtu) { +tcp_sync_mss (sk, dmtu);/* Resend the TCP packet because it's * clear that the old packet has been
@@ -1624,7 +1623,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,dst_mtu (dst)); +tcp_sync_mss (newsk,dst4_mtu (dst)); newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst));tcp_initialize_rcv_mss (newsk);
net/ipv6/sit.c +1 -1
@@ -968,7 +968,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, iph6 =ipv6_hdr (skb);if (df) { - mtu =dst_mtu (&rt->dst) - t_hlen; + mtu =dst4_mtu (&rt->dst) - t_hlen;if (mtu <IPV4_MIN_MTU ) {DEV_STATS_INC (dev, collisions);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 tcp: clamp route advmss to TCP_MIN_MSS
In reply to Sasha LevinFrom: Yong Wang <[email protected]>
[ Upstream commit 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1 ]
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.
--- 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
@@ -1475,6 +1475,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
@@ -1624,7 +1624,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
@@ -403,7 +403,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
@@ -125,7 +125,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;
@@ -3698,7 +3698,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 ();
@@ -3810,7 +3810,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
@@ -1341,7 +1341,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
Re: [PATCH 6.6.y 5/5] tcp: clamp route advmss to TCP_MIN_MSS
Quoted 125 lines · Sasha Levin
From: Yong Wang <[email protected]>
[ Upstream commit
870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1]
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_ADVMSSis 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 whenRTAX_ADVMSSis left at 0 and the effective advmss is later driven down by route MTU andmin_adv_mss.Introduce a
tcp_dst_advmss()helper that clamps route advmss toTCP_MIN_MSSbefore 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 beforetcp_select_initial_window()rounds the receive window.Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")Reported-by Vega <[email protected]>Signed-off-by Yong Wang <[email protected]>Signed-off-by Ren Wei <[email protected]>Link https://patch.msgid.link/251eaf8277fa7c66364c9815c5da01662d269181.1787074852.git.edragain@163.com open hereSigned-off-by Jakub Kicinski <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- 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@@ -1475,6 +1475,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@@ -1624,7 +1624,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@@ -403,7 +403,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@@ -125,7 +125,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;@@ -3698,7 +3698,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 ();@@ -3810,7 +3810,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@@ -1341,7 +1341,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
did not apply