The branch main has been updated by tuexen:

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

commit e46c15a0f848174f58bb08fed8e173a76b4c473a
Author:     Michael Tuexen <tue...@freebsd.org>
AuthorDate: 2025-07-19 13:03:22 +0000
Commit:     Michael Tuexen <tue...@freebsd.org>
CommitDate: 2025-07-19 13:03:22 +0000

    tcp: fix the test that a duplicate ACK has no data
    
    When processing a TCP segment, data is removed from the head or
    the tail. The test whether a segment has no data on it should
    depend on the TCP segment before the removal. Without this,
    received segments might trigger a fast retransmit even when they
    should not.
    
    Reported by:            
syzbot+fc97a2b5a0f7ea161...@syzkaller.appspotmail.com
    Reviewed by:            Peter Lei
    MFC after:              3 days
    Sponsored by:           Netflix, Inc.
    Differential Revision:  https://reviews.freebsd.org/D51425
---
 sys/netinet/tcp_input.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 7c032e13f37a..f0921032ef31 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1515,7 +1515,9 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct 
tcphdr *th,
        struct tcpopt to;
        int tfo_syn;
        u_int maxseg = 0;
+       bool no_data;
 
+       no_data = (tlen == 0);
        thflags = tcp_get_flags(th);
        tp->sackhint.last_sack_ack = 0;
        sack_changed = SACK_NOCHANGE;
@@ -1754,7 +1756,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct 
tcphdr *th,
                        tp->ts_recent = to.to_tsval;
                }
 
-               if (tlen == 0) {
+               if (no_data) {
                        if (SEQ_GT(th->th_ack, tp->snd_una) &&
                            SEQ_LEQ(th->th_ack, tp->snd_max) &&
                            !IN_RECOVERY(tp->t_flags) &&
@@ -2557,7 +2559,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct 
tcphdr *th,
 
                if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
                        maxseg = tcp_maxseg(tp);
-                       if (tlen == 0 &&
+                       if (no_data &&
                            (tiwin == tp->snd_wnd ||
                            (tp->t_flags & TF_SACK_PERMIT))) {
                                /*
@@ -3113,8 +3115,7 @@ step6:
            (tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) ||
             (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) {
                /* keep track of pure window updates */
-               if (tlen == 0 &&
-                   tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
+               if (no_data && tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
                        TCPSTAT_INC(tcps_rcvwinupd);
                tp->snd_wnd = tiwin;
                tp->snd_wl1 = th->th_seq;

Reply via email to