git: 9611bf2fed71 - stable/15 - tcp: improve credential handling in syncache

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Wed, 29 Oct 2025 09:13:37 UTC
The branch stable/15 has been updated by tuexen:

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

commit 9611bf2fed71ca62161249630f98e7eac06eff6b
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2025-10-27 22:28:59 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2025-10-29 09:09:51 +0000

    tcp: improve credential handling in syncache
    
    When adding a syncache entry, take a reference count of the
    credentials while the inp is still locked.
    Thanks to markj@ for providing a hint regarding the root cause.
    
    Reported by:            David Marker
    Reviewed by:            glebius
    Tested by:              David Marker
    Fixes:                  cbc9438f0505 ("tcp: improve ref count handling when processing SYN")
    Sponsored by:           Netflix, Inc.
    Differential Revision:  https://reviews.freebsd.org/D53380
    
    (cherry picked from commit 44cb1e857f048d2326bdc1a032ccd2c04d2bcdc9)
---
 sys/netinet/tcp_syncache.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 3cb538f7054d..3a7755e9f09e 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -1380,6 +1380,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
 	struct tcpcb *tp;
 	struct socket *rv = NULL;
 	struct syncache *sc = NULL;
+	struct ucred *cred;
 	struct syncache_head *sch;
 	struct mbuf *ipopts = NULL;
 	u_int ltflags;
@@ -1408,6 +1409,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
 	 */
 	KASSERT(SOLISTENING(so), ("%s: %p not listening", __func__, so));
 	tp = sototcpcb(so);
+	cred = V_tcp_syncache.see_other ? NULL : crhold(so->so_cred);
 
 #ifdef INET6
 	if (inc->inc_flags & INC_ISIPV6) {
@@ -1636,16 +1638,16 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
 	/*
 	 * sc_cred is only used in syncache_pcblist() to list TCP endpoints in
 	 * TCPS_SYN_RECEIVED state when V_tcp_syncache.see_other is false.
-	 * Therefore, store the credentials and take a reference count only
-	 * when needed:
+	 * Therefore, store the credentials only when needed:
 	 * - sc is allocated from the zone and not using the on stack instance.
 	 * - the sysctl variable net.inet.tcp.syncache.see_other is false.
 	 * The reference count is decremented when a zone allocated sc is
 	 * freed in syncache_free().
 	 */
-	if (sc != &scs && !V_tcp_syncache.see_other)
-		sc->sc_cred = crhold(so->so_cred);
-	else
+	if (sc != &scs && !V_tcp_syncache.see_other) {
+		sc->sc_cred = cred;
+		cred = NULL;
+	} else
 		sc->sc_cred = NULL;
 	sc->sc_port = port;
 	sc->sc_ipopts = ipopts;
@@ -1783,6 +1785,8 @@ donenoprobe:
 		tcp_fastopen_decrement_counter(tfo_pending);
 
 tfo_expanded:
+	if (cred != NULL)
+		crfree(cred);
 	if (sc == NULL || sc == &scs) {
 #ifdef MAC
 		mac_syncache_destroy(&maclabel);