From nobody Thu Aug 6 09:02:34 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hG1WZ4rbWz6mgbw for ; Thu, 06 Aug 2026 09:02:34 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hG1WZ3bMSz3WrD for ; Thu, 06 Aug 2026 09:02:34 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786006954; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=IbZSNky68rqc7xZTFKjsWqz52nWXQ32zMxAkG013c5E=; b=shkPhdXf9VT0QCQ9TepFGCcULeYvJFMm5NwnYW+iDX1u96rKBA/wJMxlXatNil4EmhRtRV 7q8qxJPWKyjROVVsdxXdVTAUr58IV9IeiK77ZnD2LEqouGW2Jio9fLwtp+dEDpvVP098SQ iIGZgUunxJsbYVLfwLf5YsX3da82+0tDZqOsmU1lZ87uLRZzyL1yqI0kVJ+tYrHYsfqxpK 7LBar/wLi+kn9f/fYSdOEQ8I669jWcSgD6KAZy8LbWUHP4RSZ9W2L/TsS0muqE0+Jz8kJR ALGLEKuhp9TJmv/hCp7ZX9rwRgRyZ65uvVC/Eu0mdxYIzUN2LZnHDUIFj6l1Nw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786006954; a=rsa-sha256; cv=none; b=G2bp0PofgOSpHs0WfpnQL4kqVX34/5go1Ty9SIsF3HXMyDmL4hXwDptaWfWHZO3ClFmAmC XnUlz4hRH/7XYrv4YpPIES7+AiI9iJANswuZJ4OzWftMuDSsgDAEJqCo6iG5xDisLpPBzf d1bHm9krcbgHcCtycEwoYkDWul50iP6Wqyjs5oihnYTY3d8sBp4QN82jsjVSCd/rqNdMG/ f0zgQsu0raYXQi9DYmdjtFI55QUNQb8Bjpvt+IJTBD8G31/M8ThewEoNao73JGWK5STsVq 4vlmmqj3Zcr3NWPLDWTbRZCZGPoJ+tybPiaAqt8rbJt2fKPOEBCziY2u+XB1og== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786006954; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=IbZSNky68rqc7xZTFKjsWqz52nWXQ32zMxAkG013c5E=; b=KwVyDjvVJRic5o8lXFJNl8KTTtrMvwioZJMdYsCn+Qx/jVYScwamaFLBvTyDzOAFv/X9B0 FeEmahim7KlXY69iO7QgCSZ7t4v10Zqnq4UHyGEStdDX9uZftKAe07gVZtPfTvBn7fDGeY OZOISMDYB7rXA9ttaU/PatOF7f+SIj7+TKRseLDRNoIKnOOZCclLbqNWazmJXDDq3IhdeF f/les9lUrc+htZJfFXOygiJc2joa7ocZZF9w10qBKkb1woGQpP10eXdPsKjvK9L5/4zjQ8 nPPNMq4KaBiliDR4gQYwxMpS0F1iBbypHzfPW7pNZJlTI8uOqBxvrHaR1PanQg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hG1WZ2CDnz5H for ; Thu, 06 Aug 2026 09:02:34 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 183ff by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 06 Aug 2026 09:02:34 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Michael Tuexen Subject: git: 9f49131806eb - stable/15 - tcp: cleanup resource handling in SYN handling List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: tuexen X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 9f49131806eb77e35934699654b74d378fe20f0e Auto-Submitted: auto-generated Date: Thu, 06 Aug 2026 09:02:34 +0000 Message-Id: <6a744daa.183ff.a7cd6a1@gitrepo.freebsd.org> The branch stable/15 has been updated by tuexen: URL: https://cgit.FreeBSD.org/src/commit/?id=9f49131806eb77e35934699654b74d378fe20f0e commit 9f49131806eb77e35934699654b74d378fe20f0e Author: Michael Tuexen AuthorDate: 2026-06-17 13:46:56 +0000 Commit: Michael Tuexen CommitDate: 2026-08-06 09:01:46 +0000 tcp: cleanup resource handling in SYN handling Handle cred, ipopts, and maclabel using the same pattern: allocate at the beginning and set to NULL when the object is transferred to a struct syncache. When exiting the function, free these objects if not transferred or when transferred to the on-stack struct syncache. This makes use of a new function syncache_release(). This fixes a use after free problem: ipopts should only be freed, if the on-stack struct syncache is used and the pointer in this structure still points to the allocated ipopts. If the ipopts are moved from the struct syncache to the struct inpcb in syncache_socket(), which is called by syncache_tfo_expand(), the pointer in the struct syncache is set to NULL. In a FreeBSD default setup this problem is mitigated by 1. TCP fast open support on the server side not being enabled (the sysctl-variable net.inet.tcp.fastopen.server_enable is 0). 2. Incoming IP packet with source routing options are not being processed by the host stack (the sysctl-variable net.inet.ip.accept_sourceroute is 0). Only if these two sysctl-variables are changed, a FreeBSD system is affected, if a server actually using TCP fast open is running. Reported by: Yuxiang Yang, Yizhou Zhao, Xuewei Feng, Qi Li, and Ke Xu from Tsinghua University using GLM5.1 from Z.ai Reviewed by: markj, rscheff Sponsored by: Netflix, Inc. Differential Revision: https://reviews.freebsd.org/D57374 (cherry picked from commit 1ed2bf1e0052df8dd6b429fc4ddd1908005f39ef) --- sys/netinet/tcp_syncache.c | 70 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index 6c072e0fec38..e655b7d9c9f9 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -223,21 +223,25 @@ static MALLOC_DEFINE(M_SYNCACHE, "syncache", "TCP syncache"); #define SCH_UNLOCK(sch) mtx_unlock(&(sch)->sch_mtx) #define SCH_LOCK_ASSERT(sch) mtx_assert(&(sch)->sch_mtx, MA_OWNED) -/* - * Requires the syncache entry to be already removed from the bucket list. - */ static void -syncache_free(struct syncache *sc) +syncache_release(struct syncache *sc) { - - if (sc->sc_ipopts) + if (sc->sc_ipopts != NULL) (void)m_free(sc->sc_ipopts); - if (sc->sc_cred) + if (sc->sc_cred != NULL) crfree(sc->sc_cred); #ifdef MAC mac_syncache_destroy(&sc->sc_label); #endif +} +/* + * Requires the syncache entry to be already removed from the bucket list. + */ +static void +syncache_free(struct syncache *sc) +{ + syncache_release(sc); uma_zfree(V_tcp_syncache.zone, sc); } @@ -1396,6 +1400,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); + bzero(&scs, sizeof(scs)); cred = V_tcp_syncache.see_other ? NULL : crhold(so->so_cred); #ifdef INET6 @@ -1520,14 +1525,15 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, if (tfo_cookie_valid) INP_RUNLOCK(inp); TCPSTAT_INC(tcps_sc_dupsyn); - if (ipopts) { + if (ipopts != NULL) { /* * If we were remembering a previous source route, * forget it and use the new one we've been given. */ - if (sc->sc_ipopts) + if (sc->sc_ipopts != NULL) (void)m_free(sc->sc_ipopts); sc->sc_ipopts = ipopts; + ipopts = NULL; } /* * Update timestamp if present. @@ -1544,14 +1550,6 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, sc->sc_flags &= ~SCF_ECN_MASK; sc->sc_flags |= tcp_ecn_syncache_add(tcp_get_flags(th), iptos); } -#ifdef MAC - /* - * Since we have already unconditionally allocated label - * storage, free it up. The syncache entry will already - * have an initialized label we can use. - */ - mac_syncache_destroy(&maclabel); -#endif TCP_PROBE5(receive, NULL, NULL, m, NULL, th); /* Retransmit SYN|ACK and reset retransmit count. */ if ((s = tcp_log_addrs(&sc->sc_inc, th, NULL, NULL))) { @@ -1582,10 +1580,9 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, * Skip allocating a syncache entry if we are just going to discard * it later. */ - if (!locked || tfo_cookie_valid) { - bzero(&scs, sizeof(scs)); + if (!locked || tfo_cookie_valid) sc = &scs; - } else { + else { sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO); if (sc == NULL) { /* @@ -1602,10 +1599,9 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, } sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO); if (sc == NULL) { - if (V_tcp_syncookies) { - bzero(&scs, sizeof(scs)); + if (V_tcp_syncookies) sc = &scs; - } else { + else { KASSERT(locked, ("%s: bucket unexpectedly unlocked", __func__)); @@ -1625,23 +1621,13 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, */ #ifdef MAC sc->sc_label = maclabel; + maclabel = NULL; #endif - /* - * 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 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 = cred; - cred = NULL; - } else - sc->sc_cred = NULL; - sc->sc_port = port; + sc->sc_cred = cred; + cred = NULL; sc->sc_ipopts = ipopts; + ipopts = NULL; + sc->sc_port = port; bcopy(inc, &sc->sc_inc, sizeof(struct in_conninfo)); sc->sc_ip_tos = ip_tos; sc->sc_ip_ttl = ip_ttl; @@ -1781,13 +1767,13 @@ donenoprobe: tfo_expanded: if (cred != NULL) crfree(cred); - if (sc == NULL || sc == &scs) { #ifdef MAC + if (maclabel != NULL) mac_syncache_destroy(&maclabel); #endif - if (ipopts) - (void)m_free(ipopts); - } + if (ipopts != NULL) + (void)m_free(ipopts); + syncache_release(&scs); return (rv); }