git: c3cc26afc922 - main - pf: stricter af checks for af-to rules

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 18 Jul 2025 09:53:06 UTC
The branch main has been updated by kp:

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

commit c3cc26afc9226d808389bca8e939f408415b72ad
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-07-09 14:48:06 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-07-18 07:33:29 +0000

    pf: stricter af checks for af-to rules
    
    An af-to pf rule must have an address family naf to use after
    translation.  Make stricter sanity checks in pf ioctl to avoid later
    crashes during packet processing.
    Reported-by: syzbot+0ef9190e7d0195496d0d@syzkaller.appspotmail.com
    OK sashan@
    
    Obtained from:  OpenBSD, bluhm <bluhm@openbsd.org>, 035d4f5430
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netpfil/pf/pf_ioctl.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 3caa0d2e3b11..937619977fd9 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2041,6 +2041,34 @@ pf_ioctl_getrules(struct pfioc_rule *pr)
 	return (0);
 }
 
+static int
+pf_rule_checkaf(struct pf_krule *r)
+{
+	switch (r->af) {
+	case 0:
+		if (r->rule_flag & PFRULE_AFTO)
+			return (EPFNOSUPPORT);
+		break;
+	case AF_INET:
+		if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET6)
+			return (EPFNOSUPPORT);
+		break;
+#ifdef INET6
+	case AF_INET6:
+		if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET)
+			return (EPFNOSUPPORT);
+		break;
+#endif /* INET6 */
+	default:
+		return (EPFNOSUPPORT);
+	}
+
+	if ((r->rule_flag & PFRULE_AFTO) == 0 && r->naf != 0)
+		return (EPFNOSUPPORT);
+
+	return (0);
+}
+
 static int
 pf_validate_range(uint8_t op, uint16_t port[2])
 {
@@ -2073,6 +2101,8 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
 
 #define	ERROUT(x)	ERROUT_FUNCTION(errout, x)
 
+	if ((error = pf_rule_checkaf(rule)))
+		ERROUT(error);
 	if (pf_validate_range(rule->src.port_op, rule->src.port))
 		ERROUT(EINVAL);
 	if (pf_validate_range(rule->dst.port_op, rule->dst.port))
@@ -3741,6 +3771,10 @@ DIOCGETRULENV_error:
 				break;
 			}
 
+			if ((error = pf_rule_checkaf(newrule))) {
+				pf_krule_free(newrule);
+				break;
+			}
 			if (newrule->ifname[0])
 				kif = pf_kkif_create(M_WAITOK);
 			pf_counter_u64_init(&newrule->evaluations, M_WAITOK);