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")
This commit is contained in:
parent
d2eb5dbd7d
commit
5f1b1f184b
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user