--- /dev/null
+From f4dca95fc0f6350918f2e6727e35b41f7f86fcce Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Thu, 23 May 2024 13:05:27 +0000
+Subject: tcp: reduce accepted window in NEW_SYN_RECV state
+
+From: Eric Dumazet <edumazet@google.com>
+
+commit f4dca95fc0f6350918f2e6727e35b41f7f86fcce upstream.
+
+Jason commit made checks against ACK sequence less strict
+and can be exploited by attackers to establish spoofed flows
+with less probes.
+
+Innocent users might use tcp_rmem[1] == 1,000,000,000,
+or something more reasonable.
+
+An attacker can use a regular TCP connection to learn the server
+initial tp->rcv_wnd, and use it to optimize the attack.
+
+If we make sure that only the announced window (smaller than 65535)
+is used for ACK validation, we force an attacker to use
+65537 packets to complete the 3WHS (assuming server ISN is unknown)
+
+Fixes: 378979e94e95 ("tcp: remove 64 KByte limit for initial tp->rcv_wnd value")
+Link: https://datatracker.ietf.org/meeting/119/materials/slides-119-tcpm-ghost-acks-00
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Acked-by: Neal Cardwell <ncardwell@google.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Link: https://lore.kernel.org/r/20240523130528.60376-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Cc: Holger Hoffstätte <holger@applied-asynchrony.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/request_sock.h | 12 ++++++++++++
+ net/ipv4/tcp_ipv4.c | 7 +------
+ net/ipv4/tcp_minisocks.c | 7 +++++--
+ net/ipv6/tcp_ipv6.c | 7 +------
+ 4 files changed, 19 insertions(+), 14 deletions(-)
+
+--- a/include/net/request_sock.h
++++ b/include/net/request_sock.h
+@@ -282,4 +282,16 @@ static inline int reqsk_queue_len_young(
+ return atomic_read(&queue->young);
+ }
+
++/* RFC 7323 2.3 Using the Window Scale Option
++ * The window field (SEG.WND) of every outgoing segment, with the
++ * exception of <SYN> segments, MUST be right-shifted by
++ * Rcv.Wind.Shift bits.
++ *
++ * This means the SEG.WND carried in SYNACK can not exceed 65535.
++ * We use this property to harden TCP stack while in NEW_SYN_RECV state.
++ */
++static inline u32 tcp_synack_window(const struct request_sock *req)
++{
++ return min(req->rsk_rcv_wnd, 65535U);
++}
+ #endif /* _REQUEST_SOCK_H */
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -1143,14 +1143,9 @@ static void tcp_v4_reqsk_send_ack(const
+ #endif
+ }
+
+- /* RFC 7323 2.3
+- * The window field (SEG.WND) of every outgoing segment, with the
+- * exception of <SYN> segments, MUST be right-shifted by
+- * Rcv.Wind.Shift bits:
+- */
+ tcp_v4_send_ack(sk, skb, seq,
+ tcp_rsk(req)->rcv_nxt,
+- req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
++ tcp_synack_window(req) >> inet_rsk(req)->rcv_wscale,
+ tcp_rsk_tsval(tcp_rsk(req)),
+ READ_ONCE(req->ts_recent),
+ 0, &key,
+--- a/net/ipv4/tcp_minisocks.c
++++ b/net/ipv4/tcp_minisocks.c
+@@ -783,8 +783,11 @@ struct sock *tcp_check_req(struct sock *
+
+ /* RFC793: "first check sequence number". */
+
+- if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
+- tcp_rsk(req)->rcv_nxt, tcp_rsk(req)->rcv_nxt + req->rsk_rcv_wnd)) {
++ if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq,
++ TCP_SKB_CB(skb)->end_seq,
++ tcp_rsk(req)->rcv_nxt,
++ tcp_rsk(req)->rcv_nxt +
++ tcp_synack_window(req))) {
+ /* Out of window: send ACK and drop. */
+ if (!(flg & TCP_FLAG_RST) &&
+ !tcp_oow_rate_limited(sock_net(sk), skb,
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -1268,15 +1268,10 @@ static void tcp_v6_reqsk_send_ack(const
+ /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
+ * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
+ */
+- /* RFC 7323 2.3
+- * The window field (SEG.WND) of every outgoing segment, with the
+- * exception of <SYN> segments, MUST be right-shifted by
+- * Rcv.Wind.Shift bits:
+- */
+ tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ?
+ tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
+ tcp_rsk(req)->rcv_nxt,
+- req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
++ tcp_synack_window(req) >> inet_rsk(req)->rcv_wscale,
+ tcp_rsk_tsval(tcp_rsk(req)),
+ READ_ONCE(req->ts_recent), sk->sk_bound_dev_if,
+ &key, ipv6_get_dsfield(ipv6_hdr(skb)), 0,