DF-3362 / fix.diff
--- a/sys/net/pf/pf_norm.c 2026-09-11 10:08:39.254979306 +0000 +++ b/sys/net/pf/pf_norm.c 2026-09-11 10:09:05.382646092 +0000 @@ -659,11 +659,32 @@ * I'll pull a rabbit out of my laptop. */ *m0 = m_dup(m, M_NOWAIT); + if (*m0 == NULL) + goto no_mem; /* From KAME Project : We have missed this! */ m_adj(*m0, (h->ip_hl << 2) - (*m0)->m_pkthdr.len); - if (*m0 == NULL) - goto no_mem; + /* NOTE (DF-3362): m_adj(9) does not unlink + * trailing mbufs whose length it zeroes while + * tail-trimming, so the m_dup()ed chain can + * keep zero-length mbufs linked after the + * header trim. m_cat() would append the + * payload after those empties and the + * single-mbuf invariant below would fire on + * INVARIANTS kernels. Unlink them. + */ + { + struct mbuf **pmp = &(*m0)->m_next; + while (*pmp != NULL) { + if ((*pmp)->m_len == 0) { + struct mbuf *zm = *pmp; + *pmp = zm->m_next; + m_free(zm); + } else { + pmp = &(*pmp)->m_next; + } + } + } KASSERT(((*m0)->m_next == NULL), ("(*m0)->m_next != NULL: %s", __func__)); @@ -681,9 +702,13 @@ h = mtod(m, struct ip *); - KASSERT(((int)m->m_len == + /* NOTE (DF-3362): the result is single-mbuf + * only when the payload fits into the header + * mbuf; assert on the recomputed total. + */ + KASSERT(((int)m->m_pkthdr.len == ntohs(h->ip_len) - precut), - ("m->m_len != h->ip_len - precut: %s", + ("m_pkthdr.len != h->ip_len - precut: %s", __func__)); h->ip_off = htons(ntohs(h->ip_off) + (precut >> 3)); |