git: 87a5d76973ca - main - pfctl: add -l to use an inherited Netlink socket

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 30 Oct 2026 14:08:08 UTC
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=87a5d76973ca8eec3e112d4c8bf89933b813fe96

commit 87a5d76973ca8eec3e112d4c8bf89933b813fe96
Author:     Avinash Duduskar <avinash.duduskar@gmail.com>
AuthorDate: 2026-10-26 14:38:11 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2026-10-30 14:07:04 +0000

    pfctl: add -l to use an inherited Netlink socket
    
    pf's Netlink commands are checked against the credentials of the socket,
    so a socket opened by a privileged process keeps its authority across a
    privilege drop and exec, as the /dev/pf descriptor passed as -p
    /dev/fd/N already does. -l takes the descriptor number of such a socket
    and uses it for every request instead of creating a new one.
    
    authpf(8) uses this to run pfctl as the logged-in user.
    
    PR:             291981
    Signed-off-by:  Avinash Duduskar <avinash.duduskar@gmail.com>
    Reviewed by:    kp
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2508
---
 sbin/pfctl/pfctl.8 | 12 +++++++++++-
 sbin/pfctl/pfctl.c | 19 +++++++++++++++----
 2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index fdc66b176e8f..a90b220db7df 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -24,7 +24,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd April 20, 2026
+.Dd October 26, 2026
 .Dt PFCTL 8
 .Os
 .Sh NAME
@@ -45,6 +45,7 @@
 .Oo Fl k
 .Ar host | network | label | id | gateway | source | nat
 .Oc Xc
+.Op Fl l Ar fd
 .Op Fl o Ar level
 .Op Fl p Ar device
 .Op Fl s Ar modifier
@@ -385,6 +386,15 @@ To remove a source from a source limiter use:
 .Pp
 .Dl # pfctl -I 1 -k source -k 192.0.2.2
 .Pp
+.It Fl l Ar fd
+Use the already open Netlink socket
+.Ar fd ,
+inherited from the parent process, instead of creating a new one.
+No other process may use the socket while
+.Nm
+runs.
+Used by
+.Xr authpf 8 .
 .It Fl M
 Kill matching states in the opposite direction (on other interfaces) when
 killing states.
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index a8a870a740a2..e73f1c4d92e7 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -349,8 +349,9 @@ usage(void)
 	fprintf(stderr,
 "usage: %s [-AdeghMmNnOPqRSrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
 	"\t[-f file] [-i interface] [-K host | network]\n"
-	"\t[-k host | network | gateway | label | id] [-o level] [-p device]\n"
-	"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
+	"\t[-k host | network | gateway | label | id] [-l fd] [-o level]\n"
+	"\t[-p device] [-s modifier] [-t table -T command [address ...]]\n"
+	"\t[-x level]\n",
 	    __progname);
 
 	exit(1);
@@ -3671,6 +3672,7 @@ main(int argc, char *argv[])
 	int	 optimize = PF_OPTIMIZE_BASIC;
 	char	 anchorname[MAXPATHLEN];
 	int	 anchor_wildcard = 0;
+	int	 nl_fd = -1;
 	char	*path;
 	const char	*idopt = NULL;
 
@@ -3678,7 +3680,7 @@ main(int argc, char *argv[])
 		usage();
 
 	while ((ch = getopt(argc, argv,
-	    "a:AdD:eqf:F:ghi:I:k:K:mMnNOo:Pp:rRs:St:T:vx:z")) != -1) {
+	    "a:AdD:eqf:F:ghi:I:k:K:l:mMnNOo:Pp:rRs:St:T:vx:z")) != -1) {
 		switch (ch) {
 		case 'a':
 			anchoropt = optarg;
@@ -3731,6 +3733,15 @@ main(int argc, char *argv[])
 			src_node_kill[src_node_killers++] = optarg;
 			mode = O_RDWR;
 			break;
+		case 'l': {
+			const char *errstr;
+
+			nl_fd = strtonum(optarg, 0, INT_MAX, &errstr);
+			if (errstr != NULL)
+				errx(1, "invalid netlink descriptor: %s",
+				    errstr);
+			break;
+		}
 		case 'm':
 			opts |= PF_OPT_MERGE;
 			break;
@@ -3894,7 +3905,7 @@ main(int argc, char *argv[])
 		altqsupport = 1;
 #endif
 	}
-	pfh = pfctl_open(pf_device);
+	pfh = pfctl_open_from_nl_fd(pf_device, nl_fd);
 	if (pfh == NULL)
 		err(1, "Failed to open netlink");