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



Reply via email to