git: 8b2feafb535d - main - pf: fix fragment hole count
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 11 Feb 2025 10:32:59 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=8b2feafb535d10a559b995c6fc2529715f927e2a
commit 8b2feafb535d10a559b995c6fc2529715f927e2a
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-02-04 16:19:55 +0000
Commit: Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-02-11 10:32:21 +0000
pf: fix fragment hole count
Fragment reassembly finishes when no holes are left in the fragment
queue. In certain overlap conditions, the hole counter was wrong
and pf(4) created an incomplete IP packet. Before adjusting the
length, remove the overlapping fragment from the queue and insert
it again afterwards. pf_frent_remove() and pf_frent_insert() adjust
the hole counter automatically.
bug reported and fix tested by Lucas Aubard with Johan Mazel, Gilles
Guette and Pierre Chifflier; OK claudio@
MFC after: 1 week
Obtained from: OpenBSD, bluhm <bluhm@openbsd.org>, 9915416fe8
Sponsored by: Rubicon Communications, LLC ("Netgate")
---
sys/netpfil/pf/pf_norm.c | 33 ++++++++++-----------------------
1 file changed, 10 insertions(+), 23 deletions(-)
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index f096ea9e493f..7290ede8d393 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -534,7 +534,6 @@ 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();
@@ -648,32 +647,20 @@ pf_fillup_fragment(struct pf_fragment_cmp *key, struct pf_frent *frent,
uint16_t aftercut;
aftercut = frent->fe_off + frent->fe_len - after->fe_off;
- DPFPRINTF(("adjust overlap %d\n", aftercut));
if (aftercut < after->fe_len) {
+ DPFPRINTF(("frag tail overlap %d", aftercut));
m_adj(after->fe_m, aftercut);
- old_index = pf_frent_index(after);
+ /* Fragment may switch queue as fe_off changes */
+ pf_frent_remove(frag, 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\n",
- 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\n"));
- m_freem(after->fe_m);
- uma_zfree(V_pf_frent_z, after);
- /* There is not way to recover */
- goto bad_fragment;
- }
+ /* 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 free_fragment;
}
break;
}