git: 1c62c8bac5ae - stable/14 - tcp: improve SEG.SEQ validation for RST segments

Michael Tuexen <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7446db.3c7d4.3eca70b__42107.5846579456$1786005226$gmane$org@gitrepo.freebsd.org>
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));
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.