From: Simon Baatz <[email protected]> When window scaling is not used, we already clamp window_clamp to 65535, but rcv_wnd/rcv_ssthresh can still remain larger than this.
Fix this by capping rcv_wnd to 65535 in the non-scaling paths of both active and passive opens. Since the advertised window in SYN and SYN/ACK segments is unscaled, this cannot shrink the window advertised to the peer. Also ensure that tcp_select_initial_window() always keeps rcv_wnd less than or equal to the (scale-limited) window_clamp. Signed-off-by: Simon Baatz <[email protected]> --- net/ipv4/tcp_input.c | 7 ++++++- net/ipv4/tcp_minisocks.c | 8 ++++++-- net/ipv4/tcp_output.c | 5 +++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7171442c3ed7a..505884dcb7a2b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6898,7 +6898,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, */ WRITE_ONCE(tp->rcv_nxt, TCP_SKB_CB(skb)->seq + 1); tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; - tp->rcv_mwnd_seq = tp->rcv_wup + tp->rcv_wnd; /* RFC1323: The window in SYN & SYN/ACK segments is * never scaled. @@ -6909,7 +6908,13 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0; WRITE_ONCE(tp->window_clamp, min(tp->window_clamp, 65535U)); + tp->rcv_ssthresh = min(tp->rcv_ssthresh, 65535U); + /* As the window in the SYN was not scaled, + * we did not advertise more than 65535. + */ + tp->rcv_wnd = min(tp->rcv_wnd, 65535U); } + tp->rcv_mwnd_seq = tp->rcv_wup + tp->rcv_wnd; if (tp->rx_opt.saw_tstamp) { tp->rx_opt.tstamp_ok = 1; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 199f0b579e89c..6496fe3b9e139 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -600,9 +600,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, newtp->rx_opt.tstamp_ok = ireq->tstamp_ok; newtp->rx_opt.sack_ok = ireq->sack_ok; newtp->window_clamp = req->rsk_window_clamp; - newtp->rcv_ssthresh = req->rsk_rcv_wnd; newtp->rcv_wnd = req->rsk_rcv_wnd; - newtp->rcv_mwnd_seq = newtp->rcv_wup + req->rsk_rcv_wnd; newtp->rx_opt.wscale_ok = ireq->wscale_ok; if (newtp->rx_opt.wscale_ok) { newtp->rx_opt.snd_wscale = ireq->snd_wscale; @@ -610,7 +608,13 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, } else { newtp->rx_opt.snd_wscale = newtp->rx_opt.rcv_wscale = 0; newtp->window_clamp = min(newtp->window_clamp, 65535U); + /* As the window in the SYN/ACK was not scaled, + * we did not advertise more than 65535. + */ + newtp->rcv_wnd = min(newtp->rcv_wnd, 65535U); } + newtp->rcv_ssthresh = newtp->rcv_wnd; + newtp->rcv_mwnd_seq = newtp->rcv_wup + newtp->rcv_wnd; newtp->snd_wnd = ntohs(tcp_hdr(skb)->window) << newtp->rx_opt.snd_wscale; newtp->max_window = newtp->snd_wnd; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8e99687526a64..bf7a12872acb3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -269,8 +269,9 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, 0, TCP_MAX_WSCALE); } /* Set the clamp no higher than max representable value */ - WRITE_ONCE(*__window_clamp, - min_t(__u32, U16_MAX << (*rcv_wscale), window_clamp)); + window_clamp = min_t(u32, U16_MAX << (*rcv_wscale), window_clamp); + WRITE_ONCE(*__window_clamp, window_clamp); + *rcv_wnd = min(*rcv_wnd, window_clamp); } /* Chose a new window to advertise, update state in tcp_sock for the -- 2.53.0

