The branch stable/14 has been updated by tuexen:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=1c62c8bac5ae5ede9b65d32b08e10ae05aa955ac

commit 1c62c8bac5ae5ede9b65d32b08e10ae05aa955ac
Author:     Michael Tuexen <[email protected]>
AuthorDate: 2026-08-03 11:07:32 +0000
Commit:     Michael Tuexen <[email protected]>
CommitDate: 2026-08-06 05:56:07 +0000

    tcp: improve SEG.SEQ validation for RST segments
    
    A RST segment can be sent in response to
    (a) received segment or
    (b) by the upper layer protocol.
    
    The SEG.SEQ validation consists of two checks:
    (1) the in-window check of SEG.SEQ and
    (2) the exact match check of SEG.SEQ.
    
    For the in-window check (1), the left edge of the window needs to be
    based on tp->last_ack_sent to cover the delayed ACK case, whereas the
    right edge needs to be based on tp->rcv_nxt + tp->rcv_wnd. This both
    assumes that tp->rcv_wnd is not zero. For the special case of
    tp->rcv_wnd being zero, add checks against tp->last_ack_sent for (a)
    and on tp->rcv_nxt for (b). This applies to all TCP stacks.
    
    When the exact match (2) of SEG.SEQ is performed, it should be based
    on tp->last_ack_sent for (a) and on tp->rcv_nxt for (b). To cover both,
    check for both. Add this only to the base stack, since the RACK and
    BBR stacks already do this.
    
    PR:                     296594
    Reviewed by:            rscheff
    Sponsored by:           Netflix, Inc.
    Differential Revision:  https://reviews.freebsd.org/D58594
    
    (cherry picked from commit c9df1a6cf9be9d44eacc8616ebba1cd19010c7fc)
---
 sys/netinet/tcp_input.c                  | 18 ++++++++++++------
 sys/netinet/tcp_stacks/rack_bbr_common.c | 22 ++++++++++++++--------
 2 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 9dfd38d679e9..5ff4597abe6c 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -2165,20 +2165,26 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct 
tcphdr *th,
                 * - RST drops connection only if SEG.SEQ == RCV.NXT.
                 * - If RST is in window, we send challenge ACK.
                 *
-                * Note: to take into account delayed ACKs, we should
-                *   test against last_ack_sent instead of rcv_nxt.
+                * Note 1: to take into account delayed ACKs, we should
+                *   test against last_ack_sent in addition to rcv_nxt.
                 * Note 2: we handle special case of closed window, not
                 *   covered by the RFC.
+                * Note 3 (XXXMT): check against rcv_adv instead of
+                *   tp->rcv_nxt + tp->rcv_wnd.
                 */
-               if ((SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
-                   SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) ||
-                   (tp->rcv_wnd == 0 && tp->last_ack_sent == th->th_seq)) {
+               if ((tp->rcv_wnd > 0 &&
+                    SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
+                    SEQ_LT(th->th_seq, tp->rcv_nxt + tp->rcv_wnd)) ||
+                   (tp->rcv_wnd == 0 &&
+                    (tp->last_ack_sent == th->th_seq ||
+                     tp->rcv_nxt == th->th_seq))) {
                        KASSERT(tp->t_state != TCPS_SYN_SENT,
                            ("%s: TH_RST for TCPS_SYN_SENT th %p tp %p",
                            __func__, th, tp));
 
                        if (V_tcp_insecure_rst ||
-                           tp->last_ack_sent == th->th_seq) {
+                           tp->last_ack_sent == th->th_seq ||
+                           tp->rcv_nxt == th->th_seq) {
                                TCPSTAT_INC(tcps_drops);
                                /* Drop the connection. */
                                switch (tp->t_state) {
diff --git a/sys/netinet/tcp_stacks/rack_bbr_common.c 
b/sys/netinet/tcp_stacks/rack_bbr_common.c
index 8b9a30a86397..28bb901dfdbf 100644
--- a/sys/netinet/tcp_stacks/rack_bbr_common.c
+++ b/sys/netinet/tcp_stacks/rack_bbr_common.c
@@ -709,18 +709,24 @@ __ctf_process_rst(struct mbuf *m, struct tcphdr *th, 
struct socket *so,
        /*
         * RFC5961 Section 3.2
         *
-        * - RST drops connection only if SEG.SEQ == RCV.NXT. - If RST is in
-        * window, we send challenge ACK.
+        * - RST drops connection only if SEG.SEQ == RCV.NXT.
+        * - If RST is in window, we send challenge ACK.
         *
-        * Note: to take into account delayed ACKs, we should test against
-        * last_ack_sent instead of rcv_nxt. Note 2: we handle special case
-        * of closed window, not covered by the RFC.
+        * Note 1: to take into account delayed ACKs, we should
+        *   test against last_ack_sent in addition to rcv_nxt.
+        * Note 2: we handle special case of closed window, not
+        *   covered by the RFC.
+        * Note 3 (XXXMT): check against rcv_adv instead of
+        *   tp->rcv_nxt + tp->rcv_wnd.
         */
        int dropped = 0;
 
-       if ((SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
-           SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) ||
-           (tp->rcv_wnd == 0 && tp->last_ack_sent == th->th_seq)) {
+       if ((tp->rcv_wnd > 0 &&
+            SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
+            SEQ_LT(th->th_seq, tp->rcv_nxt + tp->rcv_wnd)) ||
+           (tp->rcv_wnd == 0 &&
+            (tp->last_ack_sent == th->th_seq ||
+             tp->rcv_nxt == th->th_seq))) {
                KASSERT(tp->t_state != TCPS_SYN_SENT,
                    ("%s: TH_RST for TCPS_SYN_SENT th %p tp %p",
                    __func__, th, tp));

Reply via email to