wb_attach() allocates sc->wb_ldata but wb_detach() frees never-assigned sc->wb_ldata_ptr: ~296KB contigmalloc leak per attach/detach cycle
Summary
attach allocates into sc->wb_ldata but detach tests/frees sc->wb_ldata_ptr - a distinct softc field never assigned anywhere in the tree (grep-exhaustive). The guard is always false, so ~296KB of page-aligned contiguous kernel memory leaks on every detach, including all attach error paths. nfe-family attach/detach asymmetry. Free-the-right-field fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4269 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.3 KB | β raw | |
| VERDICT.md | β | 1.5 KB | β raw | |
| fix.diff | β | 891 B | view raw | |
| verdict.json | β | 2.0 KB | view raw | |
| env.txt | β | 700 B | view raw |
DF-4269 β wb_attach() allocates sc->wb_ldata but wb_detach() frees sc->wb_ldata_ptr (never assigned)
Files: sys/dev/netif/wb/if_wb.c:779-786 (attach), :852-859 (detach),
sys/dev/netif/wb/if_wbreg.h:377-378 (two distinct softc fields).
What
sc->wb_ldata = contigmalloc(sizeof(struct wb_list_data) + 8, M_DEVBUF, /* :779 */
M_WAITOK | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
...
if (sc->wb_ldata_ptr) { /* :856 */
contigfree(sc->wb_ldata_ptr, sizeof(struct wb_list_data) + 8, /* :857 */
M_DEVBUF);
}
wb_ldata_ptr (caddr_t, if_wbreg.h:377) is never assigned anywhere in the
tree (verified: only occurrences are the declaration and the detach free).
The allocation lives in sc->wb_ldata (if_wbreg.h:378). Every wb_detach()
therefore frees NULL and leaks the contigmalloc block: ~296KB
(sizeof(struct wb_list_data) + 8 = 64Γ4096 + 64Γ16 + 128Γ256 + 8) of
physically-contiguous, page-aligned kernel memory per attach/detach cycle β
including every wb_attach() error path (they tail-call wb_detach, :827-829).
Impact
Unbounded kernel memory leak on module unload (kldunload if_wb.ko) /
device removal / failed attach; repeat cycles exhaust kernel memory and
contiguous pages. Privileged trigger, hardware-gated driver.
VERDICT β DF-4269 (contigmalloc leak: wb_ldata vs wb_ldata_ptr)
Status: untested β no W89C840F hardware in the guest (env.txt). The leak
is source-certain (grep-exhaustive): wb_ldata_ptr occurs exactly twice in
the whole tree β the declaration (if_wbreg.h:377) and the detach free
(if_wb.c:856-858) β and is never set, so if (sc->wb_ldata_ptr) is always
false and the contigmalloc(sizeof(struct wb_list_data) + 8) from attach
(if_wb.c:779-780) is never returned.
Impact
- ~296KB (644096 + 6416 + 128*256 + 8 = 295,944 bytes) of page-aligned, physically-contiguous kernel memory leaked per attach/detach cycle.
- Reachable by root via kldload/kldunload of if_wb.ko on any machine (the module builds and loads without the NIC; probe fails but attach already allocated? β no: on probe failure attach never runs, so the leak strictly requires the hardware to attach, or an attach-time failure after :779 (mii_phy_probe failure, bus_setup_intr failure), which also tail-calls wb_detach and leaks.
- Severity Low: privileged unload + hardware presence; pure resource leak, no corruption.
Fix
Free sc->wb_ldata (fix.diff). The +8 size matches the allocation.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testableFix validation requires the NIC; the guest has none.
fix.diff; VERDICT.md
Confirmed kernel references
Detail
Evidence (decisive lines)
if_wb.c:779 (alloc into wb_ldata) vs if_wb.c:856-858 (free of wb_ldata_ptr); if_wbreg.h:377-378 (distinct fields); tree-wide grep for wb_ldata_ptr yields only the declaration + the free; VERDICT.md
PoC changes
No PoC (hardware-gated); analysis pack.
Verified recommended fix
Free sc->wb_ldata (the field that holds the contigmalloc result) in wb_detach.
Verdict
Source-certain memory leak. wb_attach() allocates sc->wb_ldata (if_wb.c:779-781, contigmalloc sizeof(struct wb_list_data)+8 = ~296KB page-aligned contiguous memory) but wb_detach() frees sc->wb_ldata_ptr (if_wb.c:856-859), a DIFFERENT softc field (if_wbreg.h:377-378) that is never assigned anywhere in the tree (grep-exhaustive: only the declaration and the free reference it). The guard 'if (sc->wb_ldata_ptr)' is therefore always false and the block leaks on every detach, including all wb_attach error paths (they tail-call wb_detach at if_wb.c:827-829). Root-triggered (kldunload/device removal) resource-exhaustion vector on a hardware-gated driver. Not kernel-reproduced: the guest has no W89C840F NIC (env.txt).
No comments yet.