The branch main has been updated by kp:

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

commit dda88af8fa4eb1455a6e899434936c4ddeaf526d
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2025-05-26 09:55:12 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2025-06-06 11:16:00 +0000

    pf: limit how many headers we look at
    
    Limit the nested header chain for IPv6 extensions headers and for
    authentication headers in the IPv4 case.  This prevents spending
    excessive cpu time on crafted packets.
    OK henning@
    
    Obtained from:  OpenBSD, bluhm <bl...@openbsd.org>, 2e5bc81177
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D50659
---
 sys/netpfil/pf/pf.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 0cfb728c3eb5..f1b04a96590b 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -180,6 +180,8 @@ VNET_DEFINE(u_int32_t,                       
ticket_altqs_inactive);
 VNET_DEFINE(int,                        altqs_inactive_open);
 VNET_DEFINE(u_int32_t,                  ticket_pabuf);
 
+static const int                        PF_HDR_LIMIT = 20;     /* arbitrary 
limit */
+
 VNET_DEFINE(SHA512_CTX,                         pf_tcp_secret_ctx);
 #define        V_pf_tcp_secret_ctx              VNET(pf_tcp_secret_ctx)
 VNET_DEFINE(u_char,                     pf_tcp_secret[16]);
@@ -9698,6 +9700,7 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short 
*reason)
 {
        struct ah        ext;
        u_int32_t        hlen, end;
+       int              hdr_cnt;
 
        hlen = h->ip_hl << 2;
        if (hlen < sizeof(struct ip) || hlen > ntohs(h->ip_len)) {
@@ -9710,7 +9713,7 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short 
*reason)
        /* stop walking over non initial fragments */
        if ((h->ip_off & htons(IP_OFFMASK)) != 0)
                return (PF_PASS);
-       for (;;) {
+       for (hdr_cnt = 0; hdr_cnt < PF_HDR_LIMIT; hdr_cnt++) {
                switch (pd->proto) {
                case IPPROTO_AH:
                        /* fragments may be short */
@@ -9729,6 +9732,9 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short 
*reason)
                        return (PF_PASS);
                }
        }
+       DPFPRINTF(PF_DEBUG_MISC, ("IPv4 nested authentication header limit"));
+       REASON_SET(reason, PFRES_IPOPTIONS);
+       return (PF_DROP);
 }
 
 #ifdef INET6
@@ -9801,14 +9807,13 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, 
u_short *reason)
        struct ip6_ext           ext;
        struct ip6_rthdr         rthdr;
        uint32_t                 end;
-       int                      hdr_cnt = 0, fraghdr_cnt = 0, rthdr_cnt = 0;
+       int                      hdr_cnt, fraghdr_cnt = 0, rthdr_cnt = 0;
 
        pd->off += sizeof(struct ip6_hdr);
        end = pd->off + ntohs(h->ip6_plen);
        pd->fragoff = pd->extoff = pd->jumbolen = 0;
        pd->proto = h->ip6_nxt;
-       for (;;) {
-               hdr_cnt++;
+       for (hdr_cnt = 0; hdr_cnt < PF_HDR_LIMIT; hdr_cnt++) {
                switch (pd->proto) {
                case IPPROTO_FRAGMENT:
                        if (fraghdr_cnt++) {
@@ -9863,7 +9868,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, 
u_short *reason)
                        /* FALLTHROUGH */
                case IPPROTO_HOPOPTS:
                        /* RFC2460 4.1:  Hop-by-Hop only after IPv6 header */
-                       if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 1) {
+                       if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 0) {
                                DPFPRINTF(PF_DEBUG_MISC, ("IPv6 hopopts not 
first"));
                                REASON_SET(reason, PFRES_IPOPTIONS);
                                return (PF_DROP);
@@ -9922,6 +9927,9 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, 
u_short *reason)
                        return (PF_PASS);
                }
        }
+       DPFPRINTF(PF_DEBUG_MISC, ("IPv6 nested extension header limit"));
+       REASON_SET(reason, PFRES_IPOPTIONS);
+       return (PF_DROP);
 }
 #endif /* INET6 */
 

Reply via email to