ath_hal_9287EepromAttach error paths leak the malloc'd HAL_EEPROM_9287 (~1KB permanently per failed attach): three post-malloc returns never free or install it, and ar9287Attach's bad: unwind is a no-op for it
Summary
Three error returns between the malloc and the ownership install (read failure, bad checksum, bad version) orphan the ~1KB block; the caller's detach can't free memory it was never handed (eepromDetach is a no-op until installed). EEPROM content trivially triggers it - hotplug-repeatable unbounded kernel heap exhaustion under the untrusted-EEPROM model. v14/v4k twins carry the same family bug. fail-label+free fix. [PASS-2 ATTRIBUTION: the leak code lives in ah_eeprom_9287.c:322/335/376/395 (malloc + 3 non-freeing error returns) - apply the fail-label fix there; this row covers the same defect as seen from the caller]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4873 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | file | 3.9 KB | β raw | |
| env.txt | file | 272 B | view raw | |
| fix.diff | file | 1.2 KB | view raw | |
| verdict.json | file | 3.7 KB | view raw |
DF-4873 β ath_hal_9287EepromAttach error paths leak the malloc'd HAL_EEPROM_9287 (~1KB per failed attach; ar9287Attach's bad: path cannot reclaim it)
What was verified (static, line-by-line)
-
The allocation.
sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:322-326c ee = ath_hal_malloc(sizeof(HAL_EEPROM_9287)); if (ee == AH_NULL) return HAL_ENOMEM;ath_hal_malloc=kmalloc(size, M_ATH_HAL, M_INTWAIT | M_ZERO)(ah_osdep.c:121-124).sizeof(HAL_EEPROM_9287)β 1 KB (ee_base ~0x3d0 bytes +ee_rdEdgesPower[8*12]= 96 Γ sizeof(RD_EDGES_POWER)). -
Three error returns after the allocation, none free it. - mid-image read failure β
return HAL_EEREAD;(ah_eeprom_9287.c:331-336) - bad checksum βreturn HAL_EEBADSUM;(ah_eeprom_9287.c:373-377) - bad EEPROM version βreturn HAL_EEBADSUM;(ah_eeprom_9287.c:392-396) -
Ownership is never transferred on those paths.
AH_PRIVATE(ah)->ah_eepromand theah_eepromDetach/ah_eepromGet/... ops are installed only at the very end (ah_eeprom_9287.c:400-406), after all of the error returns. -
The caller's unwind cannot reclaim it.
ar9287Attach(sys/dev/netif/ath/ath_hal/ar9002/ar9287_attach.c:239-241):c ecode = ath_hal_9287EepromAttach(ah); if (ecode != HAL_OK) goto bad; /* ar9287_attach.c:362-367 */ bad: if (ah != AH_NULL) ah->ah_detach(ah); /* == ar5416Detach (ar5416_attach.c:97) */ar5416Detach(ar5416_attach.c:490-509) callsath_hal_eepromDetach(ah)at line 507, which is the macroc #define ath_hal_eepromDetach(_ah) do { \ if (AH_PRIVATE(_ah)->ah_eepromDetach != AH_NULL) \ AH_PRIVATE(_ah)->ah_eepromDetach(_ah); \ } while (0) /* ah_internal.h:474-477 */β a no-op becauseah_eepromDetachwas never installed β thenath_hal_free(ah)frees only thestruct ath_hal_9287, notee. The ~1 KBHAL_EEPROM_9287is orphaned. Leak confirmed. -
Family bug.
v14EepromAttachhas the identical shape (ah_eeprom_v14.c:363malloc;return HAL_EEREADat ~:375 with no free);v4kmirrors it. This pack documents the ar9287 path (the audited file's call site); the v14/v4k twins should get the samefail:label.
Trigger / threat model
Untrusted-EEPROM / hostile-hardware (physical access or resold/reprogrammed card): any of the three failures is trivially produced by EEPROM content (checksum mismatch being the easiest β the attacker recomputes or corrupts it). Each attach attempt with such a card leaks ~1 KB permanently (M_ATH_HAL kernel heap, no reference, never freed). Hotplug insert/remove cycles repeat the leak without bound. No UAF, no corruption β a slow, permanent kernel memory-exhaustion hygiene bug. Severity Low.
Why no runtime PoC (untested, family precedent DF-4793/DF-4799/DF-4548)
The leak requires an AR9287 card whose EEPROM reads fail partway or fails
checksum/version β the QEMU audit guest has no Atheros NIC, so
ar9287Attach is never reached. The static ownership trace above is
complete and has no gaps (allocation β error return β caller unwind β
detach macro β nothing frees ee).
Fix
fail: label freeing ee before each post-malloc error return β see
fix.diff (git-apply-able, verified with git apply --check). Not
guest-build-validated (no reason to build a kernel for a change whose
trigger hardware is absent; change is mechanical).
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.diff authored from line-accurate root cause and verified git-apply-able; runtime fix validation impossible on the guest (no AR9287 hardware to trigger a failed eeprom attach)
findings/poc/DF-4873/fix.diff
Confirmed kernel references
- sys/dev/netif/ath/ath_hal/ar9002/ar9287_attach.c:239-241
- sys/dev/netif/ath/ath_hal/ar9002/ar9287_attach.c:362-367
- sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:322-326
- sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:331-336
- sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:373-377
- sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:392-396
- sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:400-406
- sys/dev/netif/ath/ath_hal/ah_internal.h:474-477
- sys/dev/netif/ath/ath_hal/ar5416/ar5416_attach.c:490-509
- sys/dev/netif/ath/ath_hal/ah_osdep.c:121-124
Detail
Evidence (decisive lines)
findings/poc/DF-4873/VERDICT.md (full ownership trace with path:line); findings/poc/DF-4873/fix.diff (git apply --check clean)
PoC changes
No runtime PoC possible: requires an AR9287 card whose EEPROM fails mid-read/checksum/version; no Atheros NIC on the QEMU guest. Verification is the complete static ownership trace in VERDICT.md
Verified recommended fix
Add a fail: label to ath_hal_9287EepromAttach that ath_hal_free()s the not-yet-installed ee, and route the three post-malloc error returns through it (see fix.diff)
Verdict
Kernel heap memory leak (permanent, ~1KB per failed attach) on the ar9287 EEPROM-attach error paths: ath_hal_9287EepromAttach mallocs HAL_EEPROM_9287 at ah_eeprom_9287.c:322 (ath_hal_malloc -> kmalloc M_ATH_HAL M_ZERO, ah_osdep.c:121-124), then returns HAL_EEREAD at :335 (mid-image read failure), HAL_EEBADSUM at :376 (bad checksum) or :395 (bad EEPROM version) without freeing ee and without installing it - AH_PRIVATE(ah)->ah_eeprom and the ah_eepromDetach op are set only at :400-406, after every error return. The caller's unwind (ar9287_attach.c:239-241 goto bad -> ah->ah_detach == ar5416Detach, ar5416_attach.c:490-509) calls ath_hal_eepromDetach at :507, which is a no-op when ah_eepromDetach was never installed (ah_internal.h:474-477), then ath_hal_free frees only the ath_hal itself. The HAL_EEPROM_9287 is orphaned with no back-reference. Attacker model (untrusted EEPROM / hostile card, physical access or hotplug): a corrupt or reprogrammed EEPROM trivially hits checksum/version failure; every attach attempt leaks ~1KB; hotplug cycles repeat it without bound (slow kernel memory exhaustion). Same shape as DF-4209 (legacy eeprom leak, Info) but attacker-chosen trigger content and hotplug-repeatable. Statically certain: allocation -> error return -> caller unwind -> detach macro no-op, no gap. No AR9287 NIC on the QEMU guest so no runtime PoC (family precedent DF-4793/DF-4799/DF-4548 untested). v14EepromAttach (ah_eeprom_v14.c:363+) and v4k have the identical family bug - fix them the same way.
No comments yet.