txp(4) attach error path leaks the 256 rb_sd swdesc kmallocs (and ifmedia) when txp_alloc_rings() fails after allocating them
Summary
txp_alloc_rings kmallocs 256 persistent swdescs whose only references live inside the DMA-shared ldata block; on later failure the attach fail-path frees ldata but not the swdescs (4096 bytes/failed attach); the post-ifmedia_init bus_setup_intr failure path also skips ifmedia_removeall. Bounded leak on a hardware-gated error path. Free-under-guard + ifmedia_removeall fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4234 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger.c | β | 169 B | view raw | |
| build.log | β | 77 B | view raw | |
| run.log | β | 1.2 KB | view raw | |
| env.txt | β | 688 B | view raw | |
| fix.diff | β | 1.2 KB | view raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| README.md | β | 1.6 KB | β raw | |
| verdict.json | β | 2.3 KB | view raw |
DF-4234 β txp(4) attach error path leaks the 256 rb_sd swdesc allocations (and ifmedia)
File: sys/dev/netif/txp/if_txp.c (pass 2)
Severity: Low (kernel memory leak, no attacker-reachable trigger β needs
a card whose firmware boots far enough to allocate rings but then fails the
boot-record handshake)
The bug
txp_alloc_rings() (if_txp.c:948-956) kmallocs one struct txp_swdesc
per receive-buffer slot (256 Γ 16 B) and stores the pointers only inside
the DMA-shared ring (sc_rxbufs[i].rb_sd, which is &sc->sc_ldata->
txp_rxbufs). If the function later fails (fw not running /
not waiting for boot, if_txp.c:972-991), txp_attach() does
goto fail β txp_release_resources() (if_txp.c:358-374) frees irq, res
and the whole sc_ldata block β but not the 256 kmalloc'd swdescs, whose
only references lived inside sc_ldata. ~4 KB leaked per failed attach;
repeated reprobe cycles (devctl/kldload loops on a half-broken card)
accumulate.
Secondary asymmetry: after ifmedia_init() at if_txp.c:284, the
bus_setup_intr failure path (if_txp.c:315-322) calls ether_ifdetach()
but never ifmedia_removeall() (compare txp_detach() :346).
No PoC (Low, hardware-gated error path β trigger needs a 3c990 that fails
boot-record registration). Status untested per convention; the guest probe
run.log (shared with DF-4231) shows the driver is in the kernel and no 3Com
device exists.
Fix
Free the swdescs in txp_release_resources() before freeing sc_ldata
(guarded by sc_rxbufs != NULL), and ifmedia_removeall() on the late
attach-failure path.
DF-4234 VERDICT β attach error-path swdesc leak
Verdict: source-certain Low memory leak on a hardware-gated error path; untested (no PoC β Low severity, hardware precondition).
Trace
txp_attach() if_txp.c:202
:241 txp_chip_init() ok
:248 txp_download_fw() ok
:255 sc->sc_ldata = contigmalloc(...) ok
:258 txp_alloc_rings(sc)
:948-956 for (i = 0; i < RXBUF_ENTRIES; i++)
sc->sc_rxbufs[i].rb_sd = kmalloc(sizeof(struct txp_swdesc),
M_DEVBUF, M_WAITOK);
// pointers stored ONLY inside sc_ldata
:972-991 ... READ_REG(TXP_A2H_0) != STAT_WAITING_FOR_BOOT /
!= STAT_RUNNING β return(ENXIO)
:259 error = ENXIO; goto fail;
fail:
:327 txp_release_resources(dev);
:370-371 contigfree(sc->sc_ldata, ...) // rb_sd pointers die here
// the 256 kmalloc'd swdescs are leaked (256 * 16 = 4096 bytes)
txp_detach() frees them (if_txp.c:349-350) but is only reached for
successfully-attached devices. device_is_attached() gating elsewhere
confirms attach-failure never routes through detach.
Fix in fix.diff: free rb_sd in txp_release_resources() under a
sc_rxbufs != NULL guard (it points into sc_ldata, so check before the
contigfree), plus ifmedia_removeall() for the post-ifmedia_init failure
path at :315-322 (mirroring txp_detach():346).
Not runtime-verifiable: requires a 3c990 that passes chip-init + fw download but fails the boot-record handshake (run.log: no such device on the guest). Severity Low: no unprivileged trigger, bounded leak per event.
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_testableLow-severity leak fix; not runtime-validable (hardware-gated error path). Diff is build-safe and dedups the detach free.
fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (error-path trace), fix.diff (leak fix incl. detach-loop dedup to avoid double-free), run.log (driver in kernel, NO_3COM_PCI_DEVICE)
PoC changes
n/a -- Low finding, PoC skipped per contract (verdict status 'untested').
Verified recommended fix
Free rb_sd in txp_release_resources before contigfree of sc_ldata; ifmedia_removeall on the late attach-failure path (see fix.diff).
Verdict
Source-certain Low: txp_alloc_rings() kmallocs 256 persistent swdescs whose only references live inside the DMA-shared sc_ldata block (if_txp.c:948-956); when the function later fails (fw boot-record handshake, :972-991), txp_attach's fail path runs txp_release_resources() (:326-328 -> :358-374) which frees irq/res/ldata but not the swdescs -> 4096 bytes leaked per failed attach on a half-broken card; secondary: the post-ifmedia_init bus_setup_intr failure path (:315-322) skips ifmedia_removeall(). Untested (Low, hardware-gated error path; no PoC per contract -- guest has no 3c990, run.log shared with DF-4231).
No comments yet.