Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Jul 2026 12:41:13 +0000
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 850041b02548 - main - pf: include direction in fragment key
Message-ID:  <6a620be9.1e608.63f7d9a6@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kp:

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

commit 850041b025486614243fb2d481b3adb0382b02e7
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2026-07-22 15:13:51 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2026-07-23 11:27:30 +0000

    pf: include direction in fragment key
    
    pf(4) currently ignores fragment direction (in vs. out)
    in pf_frnode_compare() function.
    
    Issue noticed and reported by Frank Denis
    
    OK @bluhm
    
    Obtained from:  OpenBSD, sashan <sashan@openbsd.org>, eaa2c80721
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netpfil/pf/pf_norm.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 348c1cafbd49..45463fc7b6d8 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -82,6 +82,7 @@ struct pf_frnode {
 	struct pf_addr		fn_dst;		/* ip destination address */
 	sa_family_t		fn_af;		/* address family */
 	u_int8_t		fn_proto;	/* protocol for fragments in fn_tree */
+	u_int8_t		fn_direction;	/* pf packet direction */
 	u_int32_t		fn_fragments;	/* number of entries in fn_tree */
 
 	RB_ENTRY(pf_frnode)	fn_entry;
@@ -155,22 +156,23 @@ static struct pf_fragment *pf_fillup_fragment(struct pf_frnode *, u_int32_t,
 		    struct pf_frent *, u_short *);
 static struct mbuf *pf_join_fragment(struct pf_fragment *);
 #ifdef INET
-static int	pf_reassemble(struct mbuf **, u_short *);
+static int	pf_reassemble(struct mbuf **, uint8_t, u_short *);
 #endif	/* INET */
 #ifdef INET6
 static int	pf_reassemble6(struct mbuf **,
-		    struct ip6_frag *, uint16_t, uint16_t, u_short *);
+		    struct ip6_frag *, uint16_t, uint16_t, uint8_t, u_short *);
 #endif	/* INET6 */
 
 #ifdef INET
 static void
-pf_ip2key(struct ip *ip, struct pf_frnode *key)
+pf_ip2key(struct ip *ip, struct pf_frnode *key, uint8_t dir)
 {
 
 	key->fn_src.v4 = ip->ip_src;
 	key->fn_dst.v4 = ip->ip_dst;
 	key->fn_af = AF_INET;
 	key->fn_proto = ip->ip_p;
+	key->fn_direction = dir;
 }
 #endif	/* INET */
 
@@ -226,6 +228,8 @@ pf_frnode_compare(struct pf_frnode *a, struct pf_frnode *b)
 		return (diff);
 	if ((diff = a->fn_af - b->fn_af) != 0)
 		return (diff);
+	if ((diff = a->fn_direction - b->fn_direction) != 0)
+		return (diff);
 	if ((diff = pf_addr_cmp(&a->fn_src, &b->fn_src, a->fn_af)) != 0)
 		return (diff);
 	if ((diff = pf_addr_cmp(&a->fn_dst, &b->fn_dst, a->fn_af)) != 0)
@@ -807,7 +811,7 @@ pf_join_fragment(struct pf_fragment *frag)
 
 #ifdef INET
 static int
-pf_reassemble(struct mbuf **m0, u_short *reason)
+pf_reassemble(struct mbuf **m0, uint8_t dir, u_short *reason)
 {
 	struct mbuf		*m = *m0;
 	struct ip		*ip = mtod(m, struct ip *);
@@ -831,7 +835,7 @@ pf_reassemble(struct mbuf **m0, u_short *reason)
 	frent->fe_off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3;
 	frent->fe_mff = ntohs(ip->ip_off) & IP_MF;
 
-	pf_ip2key(ip, &key);
+	pf_ip2key(ip, &key, dir);
 
 	if ((frag = pf_fillup_fragment(&key, ip->ip_id, frent, reason)) == NULL)
 		return (PF_DROP);
@@ -902,7 +906,7 @@ pf_reassemble(struct mbuf **m0, u_short *reason)
 #ifdef INET6
 static int
 pf_reassemble6(struct mbuf **m0, struct ip6_frag *fraghdr,
-    uint16_t hdrlen, uint16_t extoff, u_short *reason)
+    uint16_t hdrlen, uint16_t extoff, uint8_t dir, u_short *reason)
 {
 	struct mbuf		*m = *m0;
 	struct ip6_hdr		*ip6 = mtod(m, struct ip6_hdr *);
@@ -936,6 +940,7 @@ pf_reassemble6(struct mbuf **m0, struct ip6_frag *fraghdr,
 	key.fn_af = AF_INET6;
 	/* Only the first fragment's protocol is relevant. */
 	key.fn_proto = 0;
+	key.fn_direction = dir;
 
 	if ((frag = pf_fillup_fragment(&key, fraghdr->ip6f_ident, frent, reason)) == NULL) {
 		PF_FRAG_UNLOCK();
@@ -1274,7 +1279,7 @@ pf_normalize_ip(u_short *reason, struct pf_pdesc *pd)
 		PF_FRAG_LOCK();
 		DPFPRINTF(PF_DEBUG_MISC, "reass frag %d @ %d-%d",
 		    h->ip_id, fragoff, max);
-		verdict = pf_reassemble(&pd->m, reason);
+		verdict = pf_reassemble(&pd->m, pd->dir, reason);
 		PF_FRAG_UNLOCK();
 
 		if (verdict != PF_PASS)
@@ -1375,7 +1380,8 @@ pf_normalize_ip6(int off, u_short *reason,
 	if (pd->virtual_proto == PF_VPROTO_FRAGMENT) {
 		/* Returns PF_DROP or *m0 is NULL or completely reassembled
 		 * mbuf. */
-		if (pf_reassemble6(&pd->m, &frag, off, pd->extoff, reason) != PF_PASS)
+		if (pf_reassemble6(&pd->m, &frag, off, pd->extoff, pd->dir, reason)
+		    != PF_PASS)
 			return (PF_DROP);
 		if (pd->m == NULL)
 			return (PF_DROP);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a620be9.1e608.63f7d9a6>