git: b712bb84a7a7 - main - tcp: fix TCPS_CLOSED state underleak in syncache_socket()

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Mon, 07 Sep 2026 19:10:06 UTC
The branch main has been updated by glebius:

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

commit b712bb84a7a7dc229324a95170b8a77e0d9c5bec
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-09-07 19:09:40 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-09-07 19:09:40 +0000

    tcp: fix TCPS_CLOSED state underleak in syncache_socket()
    
    The syncache entry holds one TCPS_SYN_RECEIVED count that normally is
    transferred to the the newborn tp.  Upon failure syncache_socket() shall
    not use TCPSTATES_INC/TCPSTATES_DEC (see 5050df3f4aa4 why).  But when
    syncache_socket() fails in_pcbconnect(), it calls tcp_discardcb() to free
    resources that were just allocated by tcp_newtcpcb() and this
    tcp_discardcb() would do TCPSTATES_DEC(tp->t_state).  The t_state is
    TCPS_CLOSED at this point.
    
    Make tcp_discardcb() symmetrical to tcp_newtcpcb() - not responsible for
    the TCPSTATES.  Make the caller responsible for state count book keeping.
    
    Reviewed by:            tuexen
    Fixes:                  3703e1a73e0e0367c04f47f793e46495e46e647b
    Differential Revision:  https://reviews.freebsd.org/D59325
---
 sys/netinet/tcp_subr.c   | 1 -
 sys/netinet/tcp_usrreq.c | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 44288d8f344d..2320d6901fac 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2455,7 +2455,6 @@ tcp_discardcb(struct tcpcb *tp)
 		STAILQ_FOREACH_FROM_SAFE(m, &tp->t_inqueue, m_stailqpkt, prev)
 			m_freem(m);
 	}
-	TCPSTATES_DEC(tp->t_state);
 
 	if (tp->t_fb->tfb_tcp_fb_fini)
 		(*tp->t_fb->tfb_tcp_fb_fini)(tp, 1);
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 33f62a73ce2c..ff046c7ad7de 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -209,6 +209,7 @@ tcp_usr_detach(struct socket *so)
 	    tp->t_state < TCPS_SYN_SENT,
 	    ("%s: inp %p not disconnected or embryonic", __func__, inp));
 
+	TCPSTATES_DEC(tp->t_state);
 	tcp_discardcb(tp);
 	in_pcbfree(inp);
 }