git: 423b1069af74 - main - pf: ensure mbufs are writable

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Wed, 11 Sep 2024 11:18:27 UTC
The branch main has been updated by kp:

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

commit 423b1069af744e717bafb3dbd0764926e2aabd88
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-09-10 20:16:13 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-09-11 11:17:48 +0000

    pf: ensure mbufs are writable
    
    Ensure that we can modify mbufs before we start processing them. There are a
    number of paths where pf will m_copyback() or otherwise modify a packet. Ensure
    that this is safe to do.
    
    For example, ip6_forward() will m_copym() the packet before handing it to the
    output pfil hook. This results in a non-writable mbuf, which would trigger
    assertion failures (see previous commit).
    
    Reviewed by:    glebius (previous version)
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D46628
---
 sys/netpfil/pf/pf.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 70220dda935e..1535843d81b1 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -8415,6 +8415,12 @@ pf_test_eth(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 	if (m->m_flags & M_SKIP_FIREWALL)
 		return (PF_PASS);
 
+	if (__predict_false(! M_WRITABLE(*m0))) {
+		m = *m0 = m_unshare(*m0, M_NOWAIT);
+		if (*m0 == NULL)
+			return (PF_DROP);
+	}
+
 	/* Stateless! */
 	return (pf_test_eth_rule(dir, kif, m0));
 }
@@ -8553,6 +8559,12 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 		return (PF_PASS);
 	}
 
+	if (__predict_false(! M_WRITABLE(*m0))) {
+		m = *m0 = m_unshare(*m0, M_NOWAIT);
+		if (*m0 == NULL)
+			return (PF_DROP);
+	}
+
 	memset(&pd, 0, sizeof(pd));
 	TAILQ_INIT(&pd.sctp_multihome_jobs);
 	if (default_actions != NULL)
@@ -9147,6 +9159,12 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 		return (PF_DROP);
 	}
 
+	if (__predict_false(! M_WRITABLE(*m0))) {
+		m = *m0 = m_unshare(*m0, M_NOWAIT);
+		if (*m0 == NULL)
+			return (PF_DROP);
+	}
+
 	memset(&pd, 0, sizeof(pd));
 	TAILQ_INIT(&pd.sctp_multihome_jobs);
 	if (default_actions != NULL)