From nobody Mon Aug 4 08:12:02 2025 X-Original-To: dev-commits-src-main@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 4bwTmf4L0nz63lPG; Mon, 04 Aug 2025 08:12:02 +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 "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bwTmf3S9bz3tb3; Mon, 04 Aug 2025 08:12:02 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1754295122; 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=G8Oc0M/AWNFzsRFx+I10y8vNJ5+Mu05FL0adWvUO7Ck=; b=nWl7Yc9NaqABoGdy0u7qt8yaA+NknKKgLIi4qmyMLxpW2JPozStVjcFGcY9epCJliugwfP DsKF+PdPtybrUr9MSnT1NPtMVzPgt9dhcYwT99EGd1uUlWEV8QnvTKti62JvEEPHfR/XCK an5AXTg+rjbt7edGwg+eITvQl0YmpPThZwuIXE+gHFWZMjVgCSLb2bsmXT5i/s0bjRAHHl x39Cz5/9/Pw+6A4lwP+4RwH4qJtSUWJqNfYcq45mh7sBIaCXCTFy6ED1BM9t3pdlmEi8m4 r0bv5BpdJdntEKEzHZrztAraMoPCAPb5au9rxNvZ09hRLXesdAMXGdte2Ud8HA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1754295122; 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=G8Oc0M/AWNFzsRFx+I10y8vNJ5+Mu05FL0adWvUO7Ck=; b=sjILBUbBqCJOWlWqV854OKBw6esASRwI2BrKJtgwHIhXU4efIAfnpYcYSNh8nBy0c65diu +thItLnpTSU6j6sYSkKhdLD/lAIvhUgACnPKMio4cIcWt9qjnsvwj2oqdZNqSJTrHwg5UU Fw7bduxXA4GmuvOlFiYorQ1MdRo97pENfqzI/iUaSuUyuPSQq7on9YAfnTs7s8t3tTtSfh WXV3pOCgF2Z1S/8cNxo5cYYRB919955hpI9omCn6Er4EE7ZQz4w6fbDVFxFZ+rINH12gLb RQXIDo9W0wy1fnYI/xH3NtOMXCbdk5ZZBtKauJPqnAuk7g8hvZ3QRNgM243cxg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1754295122; a=rsa-sha256; cv=none; b=hu0ePm7S/4BmCyGF6eDkrFua7gxvbcvCLdpR7UG+btYb64r4XvPERQ5angMCQnrmzOOXoq XpyfCn6EgV0xb/DnPL+doLcnS+HSu/MgTbHh8Ftkot8hO8XNRqwTv+MUEB5WAqmkdhzoO7 zujn2cdgf1DxTf65pBbFO+pFhS9RnRAd9N4jLiSzH7nEZ6gUEPQOcz9+GDz38E4QxZevCM OCu7GurUjt4Ipw4muEqLy4UoUQlIGbyn3f9EffC+VOX6NGiEiEV+1ur+m0wOjomcKw5DZl t1N3IGKJQ2T1mWVWpd7X+0/checMNrSTNSLXuEaqpJb/69YkE3sBMBHLttnIfg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (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 did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4bwTmf2ym6zhKc; Mon, 04 Aug 2025 08:12:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 5748C2xx093700; Mon, 4 Aug 2025 08:12:02 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5748C2it093697; Mon, 4 Aug 2025 08:12:02 GMT (envelope-from git) Date: Mon, 4 Aug 2025 08:12:02 GMT Message-Id: <202508040812.5748C2it093697@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: 349360b17eab - main - pf: return errors from pf_route() and pf_route6() List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 349360b17eaba47be3d4e7a452e28e70a133b807 Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=349360b17eaba47be3d4e7a452e28e70a133b807 commit 349360b17eaba47be3d4e7a452e28e70a133b807 Author: Kristof Provost AuthorDate: 2025-07-28 16:00:50 +0000 Commit: Kristof Provost CommitDate: 2025-08-04 06:08:31 +0000 pf: return errors from pf_route() and pf_route6() If we fail to route the packet in pf_route()/pf_route6() (e.g. because it hit the TTL limit) we free the mbuf. If that packet is an SCTP packet that establishes extra (i.e. multihome) states we have a queued job to handle that. These jobs reference the now freed mbuf. Pass the error from pf_route()/pf_route6() on, so that pf_sctp_multihome_delayed() doesn't attempt to use the invalid mbuf pointer (or establishes states for a packet we're not passing). PR: 288274 Reported by: Robert Morris Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D51627 --- sys/netpfil/pf/pf.c | 66 ++++++++++++++++++++++++++++++------------- tests/sys/netpfil/pf/nat64.py | 28 ++++++++++++++++++ 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index f6ee02626624..4801b3e2c766 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -409,14 +409,14 @@ static void pf_mtag_free(struct m_tag *); static void pf_packet_rework_nat(struct pf_pdesc *, int, struct pf_state_key *); #ifdef INET -static void pf_route(struct pf_krule *, +static int pf_route(struct pf_krule *, struct ifnet *, struct pf_kstate *, struct pf_pdesc *, struct inpcb *); #endif /* INET */ #ifdef INET6 static void pf_change_a6(struct pf_addr *, u_int16_t *, struct pf_addr *, u_int8_t); -static void pf_route6(struct pf_krule *, +static int pf_route6(struct pf_krule *, struct ifnet *, struct pf_kstate *, struct pf_pdesc *, struct inpcb *); #endif /* INET6 */ @@ -8914,7 +8914,7 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kkif *kif, } #ifdef INET -static void +static int pf_route(struct pf_krule *r, struct ifnet *oifp, struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) { @@ -8929,6 +8929,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, uint16_t tmp; int r_dir; bool skip_test = false; + int action = PF_PASS; KASSERT(pd->m && r && oifp, ("%s: invalid parameters", __func__)); @@ -8950,6 +8951,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, m0 = pd->m; pd->m = NULL; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad_locked; } @@ -8963,11 +8965,12 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, } if (ifp == oifp) { /* When the 2nd interface is not skipped */ - return; + return (action); } else { m0 = pd->m; pd->m = NULL; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } } else { @@ -8975,7 +8978,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, if (((m0 = m_dup(pd->m, M_NOWAIT)) == NULL)) { if (s) PF_STATE_UNLOCK(s); - return; + return (action); } } } else { @@ -8984,7 +8987,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, pf_dummynet(pd, s, r, &pd->m); if (s) PF_STATE_UNLOCK(s); - return; + return (action); } else { if (r_dir == PF_IN) { skip_test = true; @@ -9024,6 +9027,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, pf_send_icmp(m0, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, pd->af, r, pd->act.rtableid); + action = PF_DROP; goto bad_locked; } ip->ip_ttl -= IPTTLDEC; @@ -9070,6 +9074,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, if (ifp == NULL) { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); goto bad; } @@ -9080,9 +9085,11 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, if (pd->dir == PF_IN && !skip_test) { if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp, &pd->act) != PF_PASS) { + action = PF_DROP; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); goto bad; } else if (m0 == NULL) { + action = PF_DROP; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); goto done; } @@ -9090,6 +9097,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, DPFPRINTF(PF_DEBUG_URGENT, "%s: m0->m_len < sizeof(struct ip)", __func__); SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } ip = mtod(m0, struct ip *); @@ -9171,12 +9179,14 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, ifp->if_mtu, pd->af, r, pd->act.rtableid); } SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist); if (error) { SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } @@ -9203,7 +9213,9 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, done: if (pd->act.rt != PF_DUPTO) pd->m = NULL; - return; + else + action = PF_PASS; + return (action); bad_locked: if (s) @@ -9215,7 +9227,7 @@ bad: #endif /* INET */ #ifdef INET6 -static void +static int pf_route6(struct pf_krule *r, struct ifnet *oifp, struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) { @@ -9226,6 +9238,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, struct ifnet *ifp = NULL; int r_dir; bool skip_test = false; + int action = PF_PASS; KASSERT(pd->m && r && oifp, ("%s: invalid parameters", __func__)); @@ -9246,6 +9259,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, pd->pf_mtag->routed++ > 3) { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad_locked; } @@ -9260,10 +9274,11 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, } if (ifp == oifp) { /* When the 2nd interface is not skipped */ - return; + return (action); } else { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9272,7 +9287,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, if (((m0 = m_dup(pd->m, M_NOWAIT)) == NULL)) { if (s) PF_STATE_UNLOCK(s); - return; + return (action); } } } else { @@ -9281,7 +9296,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, pf_dummynet(pd, s, r, &pd->m); if (s) PF_STATE_UNLOCK(s); - return; + return (action); } else { if (r_dir == PF_IN) { skip_test = true; @@ -9321,6 +9336,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, pf_send_icmp(m0, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0, pd->af, r, pd->act.rtableid); + action = PF_DROP; goto bad_locked; } ip6->ip6_hlim -= IPV6_HLIMDEC; @@ -9375,6 +9391,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, if (ifp == NULL) { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9385,9 +9402,11 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, if (pd->dir == PF_IN && !skip_test) { if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT, ifp, &m0, inp, &pd->act) != PF_PASS) { + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } else if (m0 == NULL) { + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto done; } @@ -9395,6 +9414,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, DPFPRINTF(PF_DEBUG_URGENT, "%s: m0->m_len < sizeof(struct ip6_hdr)", __func__); + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9470,6 +9490,7 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, pf_send_icmp(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu, pd->af, r, pd->act.rtableid); } + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9477,7 +9498,9 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, done: if (pd->act.rt != PF_DUPTO) pd->m = NULL; - return; + else + action = PF_PASS; + return (action); bad_locked: if (s) @@ -11033,15 +11056,18 @@ done: break; } #ifdef INET - if (pd.naf == AF_INET) - pf_route(r, kif->pfik_ifp, s, &pd, inp); + if (pd.naf == AF_INET) { + action = pf_route(r, kif->pfik_ifp, s, &pd, + inp); + } #endif /* INET */ #ifdef INET6 - if (pd.naf == AF_INET6) - pf_route6(r, kif->pfik_ifp, s, &pd, inp); + if (pd.naf == AF_INET6) { + action = pf_route6(r, kif->pfik_ifp, s, &pd, + inp); +} #endif /* INET6 */ *m0 = pd.m; - action = PF_PASS; goto out; break; default: @@ -11050,13 +11076,15 @@ done: #ifdef INET case AF_INET: /* pf_route() returns unlocked. */ - pf_route(r, kif->pfik_ifp, s, &pd, inp); + action = pf_route(r, kif->pfik_ifp, s, &pd, + inp); break; #endif /* INET */ #ifdef INET6 case AF_INET6: /* pf_route6() returns unlocked. */ - pf_route6(r, kif->pfik_ifp, s, &pd, inp); + action = pf_route6(r, kif->pfik_ifp, s, &pd, + inp); break; #endif /* INET6 */ } diff --git a/tests/sys/netpfil/pf/nat64.py b/tests/sys/netpfil/pf/nat64.py index a5890fc4a161..0908c90c34a0 100644 --- a/tests/sys/netpfil/pf/nat64.py +++ b/tests/sys/netpfil/pf/nat64.py @@ -326,3 +326,31 @@ class TestNAT64(VnetTestTemplate): packets = sp.sniff(iface=ifname, timeout=5) for r in packets: r.show() + + @pytest.mark.require_user("root") + @pytest.mark.require_progs(["scapy"]) + def test_ttl_zero(self): + """ + PR 288274: we can use an mbuf after free on TTL = 0 + """ + ifname = self.vnet.iface_alias_map["if1"].name + gw_mac = self.vnet.iface_alias_map["if1"].epairb.ether + ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1") + + import scapy.all as sp + + pkt = sp.Ether(dst=gw_mac) \ + / sp.IPv6(dst="64:ff9b::192.0.2.2", hlim=0) \ + / sp.SCTP(sport=1111, dport=2222) \ + / sp.SCTPChunkInit(init_tag=1, n_in_streams=1, n_out_streams=1, \ + a_rwnd=1500, params=[ \ + sp.SCTPChunkParamIPv4Addr() \ + ]) + pkt.show() + sp.hexdump(pkt) + s = DelayedSend(pkt, sendif=ifname) + + packets = sp.sniff(iface=ifname, timeout=5) + for r in packets: + r.show() +