The branch main has been updated by kp:

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

commit 5f1b1f184b7f12330cf4a027e3db7c6700c67640
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2021-02-25 07:07:36 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2021-02-25 20:51:08 +0000

    pf: Fix incorrect fragment handling
    
    A sequence of overlapping IPv4 fragments could crash the kernel in
    pf due to an assertion.
    
    Reported by:    Alexander Bluhm
    Obtained from:  OpenBSD
    MFC after:      3 days
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netpfil/pf/pf_norm.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index b7a84437630b..d7310c7bccb4 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -549,6 +549,7 @@ pf_fillup_fragment(struct pf_fragment_cmp *key, struct 
pf_frent *frent,
        struct pf_frent         *after, *next, *prev;
        struct pf_fragment      *frag;
        uint16_t                total;
+       int                     old_index, new_index;
 
        PF_FRAG_ASSERT();
 
@@ -660,8 +661,30 @@ pf_fillup_fragment(struct pf_fragment_cmp *key, struct 
pf_frent *frent,
                DPFPRINTF(("adjust overlap %d\n", aftercut));
                if (aftercut < after->fe_len) {
                        m_adj(after->fe_m, aftercut);
+                       old_index = pf_frent_index(after);
                        after->fe_off += aftercut;
                        after->fe_len -= aftercut;
+                       new_index = pf_frent_index(after);
+                       if (old_index != new_index) {
+                               DPFPRINTF(("frag index %d, new %d",
+                                   old_index, new_index));
+                               /* Fragment switched queue as fe_off changed */
+                               after->fe_off -= aftercut;
+                               after->fe_len += aftercut;
+                               /* Remove restored fragment from old queue */
+                               pf_frent_remove(frag, after);
+                               after->fe_off += aftercut;
+                               after->fe_len -= aftercut;
+                               /* Insert into correct queue */
+                               if (pf_frent_insert(frag, after, prev)) {
+                                       DPFPRINTF(
+                                           ("fragment requeue limit 
exceeded"));
+                                       m_freem(after->fe_m);
+                                       uma_zfree(V_pf_frent_z, after);
+                                       /* There is not way to recover */
+                                       goto bad_fragment;
+                               }
+                       }
                        break;
                }
 
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to