in_delayed_cksum writes through unchecked m_pullup return and silently drops the (possibly reallocated) mbuf pointer
Summary
in_delayed_cksum calls m_pullup to coalesce transport checksum field into first mbuf but (a) never checks return for NULL before dereferencing at :951 and (b) takes mbuf by value so callers (ip_output:641 ip_fragment:802 ip_mloopback:1881) never see new pointer m_pullup may return. Under rare condition where m_pullup takes allocate-new-head branch allocation failure panics kernel via NULL->m_data deref. Successful reallocation leaves every caller holding freed pointer UAF on subsequent m->m_pkthdr.csum_flags write and ifp->if_output handoff. Other two m_pullup callers in this file both NULL-check return this one is outlier. XXX comment at :944-947 shows authors knew layout assumption fragile. Trigger requires non-standard mbuf layout M_EXT/headroom-short/m_next==NULL not reachable from standard UDP/TCP/RAWOUTPUT paths. [VERIFIED pass2: reproduced mechanism - cluster-head split forces m_pullup allocate-new-head branch leaving caller-held pointer on freed mbuf; no standard-path trigger demonstrated; NULL-check fix in combined kernel]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2565 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| rig.c | β | 5.7 KB | view raw | |
| gen.sh | β | 361 B | view raw | |
| build.sh | β | 95 B | view raw | |
| run.sh | β | 90 B | view raw | |
| run.log | β | 646 B | view raw |
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
cksum2565_run.log mode 0: caller-held m invalid after the call (stale pointer to freed head); control clean
PoC changes
verbatim extract; cluster-head chain forces the reallocation branch
Verified recommended fix
NULL-check the m_pullup return and return the (possibly new) m to callers (in combined fix kernel)
Verdict
Both code defects verified against the verbatim in_delayed_cksum (ip_output.c:929-952): (a) the m_pullup return is used without a NULL check (a too-short chain makes the pullup fail and the next line writes through NULL+offset); (b) m is taken by value -- a cluster-backed head with zero leading space (M_EXT) forces m_pullups allocate-new-head branch (uipc_mbuf.c), which FREES the old head, and every caller (ip_output.c:641/802, ip_mloopback) keeps the stale pointer. Harness: split-header input left the callers pointer targeting a consumed mbuf (m_len=0 read through it) while the checksum went into the new head. No standard TCP/UDP/RAWOUTPUT path was shown to produce the required non-contiguous layout (XXX comment at :944 acknowledges this); impact beyond the demonstrated mechanism: hardening.
No comments yet.