git: 275ff85b254c - main - pf: fix struct pf_krule_global leak

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Tue, 02 Sep 2025 21:10:58 UTC
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=275ff85b254c1f160f965dd9dbb5801f66022eab

commit 275ff85b254c1f160f965dd9dbb5801f66022eab
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-09-01 08:32:30 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-09-02 21:10:21 +0000

    pf: fix struct pf_krule_global leak
    
    Make sure we free all of the trees we allocated when we free the ruleset.
    Found by 'kldunload pf' after a test run, now that the allocation is done from a
    pf-specific malloc type.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/net/pfvar.h             | 1 +
 sys/netpfil/pf/pf_ioctl.c   | 2 +-
 sys/netpfil/pf/pf_ruleset.c | 6 ++++++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 79855fa84359..f73420494000 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -2614,6 +2614,7 @@ struct pf_kruleset	*pf_find_kruleset(const char *);
 struct pf_kruleset	*pf_get_leaf_kruleset(char *, char **);
 struct pf_kruleset	*pf_find_or_create_kruleset(const char *);
 void			 pf_rs_initialize(void);
+void			 pf_rule_tree_free(struct pf_krule_global *);
 
 
 struct pf_krule		*pf_krule_alloc(void);
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 934eff020074..06c40a03f575 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -1189,7 +1189,7 @@ pf_rule_tree_alloc(int flags)
 	return (tree);
 }
 
-static void
+void
 pf_rule_tree_free(struct pf_krule_global *tree)
 {
 
diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c
index 259f586fa127..1711e690f6bb 100644
--- a/sys/netpfil/pf/pf_ruleset.c
+++ b/sys/netpfil/pf/pf_ruleset.c
@@ -336,6 +336,12 @@ pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
 	int			 i;
 
 	while (ruleset != NULL) {
+		for (int i = 0; i < PF_RULESET_MAX; i++) {
+			pf_rule_tree_free(ruleset->rules[i].active.tree);
+			ruleset->rules[i].active.tree = NULL;
+			pf_rule_tree_free(ruleset->rules[i].inactive.tree);
+			ruleset->rules[i].inactive.tree = NULL;
+		}
 		if (ruleset == &pf_main_ruleset ||
 		    !RB_EMPTY(&ruleset->anchor->children) ||
 		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||