Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Feb 2021 15:57:11 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 86ebf4d3e12c - stable/13 - pf: Fix incorrect fragment handling
Message-ID:  <202102281557.11SFvBPJ086515@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kp:

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

commit 86ebf4d3e12c3eae94d3e9a8dcf5bd5741889b58
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-02-25 07:07:36 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-02-28 15:16:29 +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")
    
    (cherry picked from commit 5f1b1f184b7f12330cf4a027e3db7c6700c67640)
---
 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;
 		}
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102281557.11SFvBPJ086515>