plip: sc_ifbuf leaked on every down/up cycle (and on BUS_SETUP_INTR failure) β unbounded kernel heap leak
Summary
The UP transition allocates sc_ifbuf unconditionally over the previous buffer and DOWN frees nothing: each cycle leaks mtu+MLPIPHDRLEN bytes. REPRODUCED on guest: 20 cycles at mtu 65535 leaked 1.33MB (vmstat devbuf accounting, +20 allocations). Free-before-alloc fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4659 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| run.log | β | 849 B | view raw | |
| env.txt | β | 271 B | view raw | |
| README.md | β | 976 B | β raw | |
| VERDICT.md | β | 1.4 KB | β raw |
DF-4659 β sc_ifbuf leaked on every down/up cycle
File: sys/dev/netif/plip/if_plip.c:332-333 (UP transition), :306-314 (DOWN transition frees nothing), :336-341 (BUS_SETUP_INTR failure path also overwrites) Class: CWE-401 memory leak β Low severity (root-gated ioctl), certain Verdict: REPRODUCED (kernel heap leak)
Repro (guest, run.log)
root, mtu 65535: vmstat -m devbuf BEFORE (1.34M / 236 allocs) -> 20 x (ifconfig lp0 down; ifconfig lp0 up) -> AFTER 2.67M / 256 allocs: +1.33MB / +20 allocations = one leaked mtu+14 (65549B) buffer per cycle, exactly 20 x 65549 = 1.31MB.
Cause: the UP branch allocates sc_ifbuf unconditionally without freeing the previous allocation (down path never frees it; the buffer is only freed by SIOCSIFMTU). Repeatable without bound -> kernel memory exhaustion. (SIOCSIFMTU itself is properly paired.)
Fix: free any existing sc_ifbuf before the kmalloc at :332 (and on the BUS_SETUP_INTR failure path at :336-341).
DF-4659 β sc_ifbuf leaked on every down/up cycle
File: sys/dev/netif/plip/if_plip.c:332-333 (UP transition), :306-314 (DOWN transition frees nothing), :336-341 (BUS_SETUP_INTR failure path also overwrites) Class: CWE-401 memory leak β Low severity (root-gated ioctl), certain Verdict: REPRODUCED (kernel heap leak)
Repro (guest, run.log)
root, mtu 65535: vmstat -m devbuf BEFORE (1.34M / 236 allocs) -> 20 x (ifconfig lp0 down; ifconfig lp0 up) -> AFTER 2.67M / 256 allocs: +1.33MB / +20 allocations = one leaked mtu+14 (65549B) buffer per cycle, exactly 20 x 65549 = 1.31MB.
Cause: the UP branch allocates sc_ifbuf unconditionally without freeing the previous allocation (down path never frees it; the buffer is only freed by SIOCSIFMTU). Repeatable without bound -> kernel memory exhaustion. (SIOCSIFMTU itself is properly paired.)
Fix: free any existing sc_ifbuf before the kmalloc at :332 (and on the BUS_SETUP_INTR failure path at :336-341).
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.
(No fix.diff for this item: documented recommendation only - see Fix above.)
Fix verification
not_testablenot validated (Low; one-line kfree of prior buffer before kmalloc at :332)
Confirmed kernel references
Detail
Exploit chain
root ioctl loop (ifconfig down/up) -> unbounded M_DEVBUF leak -> kernel memory exhaustion (panic/system failure). Root-gated, hence Low.
Evidence (decisive lines)
run.log: devbuf 1.34M/236 -> 2.67M/256 after exactly 20 cycles at mtu 65535
PoC changes
none (ifconfig-only)
Verified recommended fix
if (sc->sc_ifbuf) kfree(sc->sc_ifbuf, M_DEVBUF); before the kmalloc at if_plip.c:332 (same on the BUS_SETUP_INTR error path)
Verdict
Kernel heap leak reproduced: the SIOCSIFFLAGS UP transition (if_plip.c:332) overwrites sc_ifbuf with a fresh kmalloc(if_mtu+14) without freeing the previous buffer; the DOWN transition (:306-314) never frees it. Measured on the guest: 20 down/up cycles at mtu 65535 leaked 1.33MB (20 x 65549B, vmstat -m devbuf 1.34M->2.67M, +20 allocations). Unbounded, root-repeatable -> memory exhaustion.
No comments yet.