git: 76afcbb52492 - main - pf: handle multiple IPv6 fragment headers

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 04 Aug 2023 13:59:14 UTC
The branch main has been updated by kp:

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

commit 76afcbb52492f9b3e72ee7d4c4ed0a54c25e1c48
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-07-13 08:25:49 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-08-04 13:23:49 +0000

    pf: handle multiple IPv6 fragment headers
    
    With 'scrub fragment reassemble' if a packet contains multiple IPv6
    fragment headers we would reassemble the packet and immediately
    continue processing it.
    
    That is, we'd remove the first fragment header and expect the next
    header to be a final header (i.e. TCP, UDP, ICMPv6, ...). However, if
    it's another fragment header we'd not treat the packet correctly.
    That is, we'd fail to recognise the payload and treat it as if it were
    an IPv6 fragment rather than as its actual payload.
    
    Fix this by restarting the normalisation on the reassembled packet.
    If there are multiple fragment headers drop the packet.
    
    Reported by:    Enrico Bassetti bassetti@di.uniroma1.it (NetSecurityLab @ Sapienza University of Rome)
    MFC after:      instant
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netpfil/pf/pf_norm.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 6dda410d8327..d3fb5dcc00ab 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -1254,6 +1254,8 @@ pf_normalize_ip6(struct mbuf **m0, struct pfi_kkif *kif,
 	if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len)
 		goto drop;
 
+again:
+	h = mtod(m, struct ip6_hdr *);
 	plen = ntohs(h->ip6_plen);
 	/* jumbo payload option not supported */
 	if (plen == 0)
@@ -1322,6 +1324,8 @@ pf_normalize_ip6(struct mbuf **m0, struct pfi_kkif *kif,
 	return (PF_PASS);
 
  fragment:
+	if (pd->flags & PFDESC_IP_REAS)
+		return (PF_DROP);
 	if (sizeof(struct ip6_hdr) + plen > m->m_pkthdr.len)
 		goto shortpkt;
 
@@ -1339,7 +1343,7 @@ pf_normalize_ip6(struct mbuf **m0, struct pfi_kkif *kif,
 		return (PF_DROP);
 
 	pd->flags |= PFDESC_IP_REAS;
-	return (PF_PASS);
+	goto again;
 
  shortpkt:
 	REASON_SET(reason, PFRES_SHORT);