git: 110801814911 - main - pf: Clear only the part of the packet descriptor that is read first

From: R. Christian McDonald <rcm_at_FreeBSD.org>
Date: Wed, 28 Oct 2026 16:00:48 UTC
The branch main has been updated by rcm:

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

commit 11080181491144b9cad726bb6e84d87fa05a681e
Author:     R. Christian McDonald <rcm@FreeBSD.org>
AuthorDate: 2026-10-28 16:00:03 +0000
Commit:     R. Christian McDonald <rcm@FreeBSD.org>
CommitDate: 2026-10-28 16:00:03 +0000

    pf: Clear only the part of the packet descriptor that is read first
    
    pf_init_pdesc() cleared the whole structure, 336 bytes on amd64, for
    every packet and twice for a forwarded one.  kif, m, pf_mtag, act and
    the SCTP job list are set before they are read, so move them to the end
    and clear only the 240 bytes before them.  On amd64 that also stays
    below the 256 bytes from which memset() switches to rep stosb.
    
    Reviewed by:            kp
    Sponsored by:           Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D60948
---
 sys/net/pfvar.h     | 14 +++++++++-----
 sys/netpfil/pf/pf.c |  4 +++-
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 6c7c7d364ba2..5b4d87a22301 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1950,9 +1950,6 @@ struct pf_pdesc {
 	struct pf_addr	 nsaddr;	/* src address after NAT */
 	struct pf_addr	 ndaddr;	/* dst address after NAT */
 
-	struct pfi_kkif	*kif;		/* incomming interface */
-	struct mbuf	*m;
-
 	struct pf_addr	*src;		/* src address */
 	struct pf_addr	*dst;		/* dst address */
 	struct pf_addr	 osrc;
@@ -1964,8 +1961,6 @@ struct pf_pdesc {
 	u_int16_t	 odport;
 	u_int16_t	 nsport;	/* src port after NAT */
 	u_int16_t	 ndport;	/* dst port after NAT */
-	struct pf_mtag	*pf_mtag;
-	struct pf_rule_actions	act;
 
 	u_int32_t	 off;		/* protocol header offset */
 	bool		 df;		/* IPv4 Don't fragment flag. */
@@ -2011,6 +2006,15 @@ struct pf_pdesc {
 	u_int16_t	 sctp_dummy_sum;
 	struct pf_krule	*related_rule;
 
+	/*
+	 * pf_init_pdesc() zeroes the members above this point only; those
+	 * below are set before they are read.
+	 */
+#define	pd_endzero	kif
+	struct pfi_kkif	*kif;		/* incoming interface */
+	struct mbuf	*m;
+	struct pf_mtag	*pf_mtag;
+	struct pf_rule_actions	 act;
 	struct pf_sctp_multihome_jobs	sctp_multihome_jobs;
 };
 
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 5961039bbb87..94985f47677c 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -11279,7 +11279,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
 static void
 pf_init_pdesc(struct pf_pdesc *pd, struct mbuf *m)
 {
-	memset(pd, 0, sizeof(*pd));
+	memset(pd, 0, offsetof(struct pf_pdesc, pd_endzero));
 	pd->pf_mtag = pf_find_mtag(m);
 	pd->m = m;
 }
@@ -11301,6 +11301,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
 	TAILQ_INIT(&pd->sctp_multihome_jobs);
 	if (default_actions != NULL)
 		memcpy(&pd->act, default_actions, sizeof(pd->act));
+	else
+		memset(&pd->act, 0, sizeof(pd->act));
 
 	if (pd->pf_mtag && pd->pf_mtag->dnpipe) {
 		pd->act.dnpipe = pd->pf_mtag->dnpipe;