git: 68831d2a2cbb - main - pf: Register the netlink family only while the vnets are set up

From: R. Christian McDonald <rcm_at_FreeBSD.org>
Date: Tue, 13 Oct 2026 19:23:01 UTC
The branch main has been updated by rcm:

URL: https://cgit.FreeBSD.org/src/commit/?id=68831d2a2cbb34e8daf24db7e4e15b8c09451f85

commit 68831d2a2cbb34e8daf24db7e4e15b8c09451f85
Author:     R. Christian McDonald <rcm@FreeBSD.org>
AuthorDate: 2026-10-13 19:22:30 +0000
Commit:     R. Christian McDonald <rcm@FreeBSD.org>
CommitDate: 2026-10-13 19:22:30 +0000

    pf: Register the netlink family only while the vnets are set up
    
    pf_modevent() registers the generic netlink family at MOD_LOAD, before
    vnet_pf_init() has set up the state hashes and locks the handlers use,
    and pf_unload() unregisters it after vnet_pf_uninit() has torn them
    down.  Sending PFNL_CMD_GETSTATES while pf loads or unloads panics in
    pf_handle_getstates() on a NULL or freed V_pf_idhash.
    
    Register the family from a SYSINIT ordered after vnet_pf_init(), and
    unregister it from the matching SYSUNINIT, before vnet_pf_uninit().
    
    Reviewed by:            kp
    Fixes:                  2cef62886dc7 ("pf: convert state retrieval to netlink")
    MFC after:              1 week
    Sponsored by:           Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D60651
---
 sys/netpfil/pf/pf_ioctl.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 45712f80cad7..174582776fa7 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -7982,8 +7982,6 @@ pf_unload(void *dummy __unused)
 	}
 	sx_xunlock(&pf_end_lock);
 
-	pf_nl_unregister();
-
 	if (pf_dev != NULL)
 		destroy_dev(pf_dev);
 
@@ -8011,6 +8009,26 @@ SYSUNINIT(pf_unload, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND, pf_unload, NULL);
 VNET_SYSUNINIT(vnet_pf_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
     vnet_pf_uninit, NULL);
 
+/*
+ * The netlink handlers use the per-vnet state: register them after
+ * vnet_pf_init() and unregister them before vnet_pf_uninit().
+ */
+static void
+pf_nl_init(void *unused __unused)
+{
+
+	pf_nl_register();
+}
+SYSINIT(pf_nl, SI_SUB_PROTO_FIREWALL, SI_ORDER_FOURTH, pf_nl_init, NULL);
+
+static void
+pf_nl_uninit(void *unused __unused)
+{
+
+	pf_nl_unregister();
+}
+SYSUNINIT(pf_nl, SI_SUB_PROTO_FIREWALL, SI_ORDER_FOURTH, pf_nl_uninit, NULL);
+
 static int
 pf_modevent(module_t mod, int type, void *data)
 {
@@ -8019,7 +8037,6 @@ pf_modevent(module_t mod, int type, void *data)
 	switch(type) {
 	case MOD_LOAD:
 		error = pf_load();
-		pf_nl_register();
 		break;
 	case MOD_UNLOAD:
 		/* Handled in SYSUNINIT(pf_unload) to ensure it's done after