⬢ DragonFlyBSD Kernel Audit
DF-4956 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4956",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "Kernel heap memory leak (permanent, 1152 bytes per failed attach) on the v4k EEPROM-attach error paths of ath_hal_v4kEepromAttach: the HAL_EEPROM_v4k mallocd at ah_eeprom_v4k.c:311 is orphaned by three post-malloc returns \u2014 HAL_EEREAD at :324 (mid-image read failure), HAL_EEBADSUM at :366 (bad checksum) and :385 (bad version) \u2014 none of which free it, and AH_PRIVATE(ah)->ah_eeprom / ah_eepromDetach are installed only at :390-396 after every error return. The caller unwind (ar9285_attach.c:246-248 goto bad -> ah_detach -> ar5416Detach:507 -> ath_hal_eepromDetach macro, ah_internal.h:474-477) is a no-op for it. Third and final member of the eeprom-attach leak family (DF-4873 ar9287 ~1KB, DF-4913 v14 4.8KB verified live, DF-1995 ar5210), predicted by both prior verdicts. Reproduced on the guest by calling the real in-kernel function with a synthetic ath_hal whose eepromRead callback serves crafted v4k images (image base owl_eep_start_loc==64): 3 failure modes x 200 attaches orphaned 600 blocks / 675K of malloc type ath_hal (permanent across kldunload), a second trigger round stacked to 1.17K blocks / 1.32M, while 200 valid attach+detach control cycles left in-use unchanged. Attacker model: untrusted EEPROM / hostile ar9285 card (physical access or hotplug) with corrupt checksum/version \u2014 every attach fails identically, repeatable without bound.",
  "exploit_chain": "",
  "evidence": "run.log (vmstat -m ath_hal 0 -> 600 blocks/675K, unchanged after kldunload), run.2.log (600 -> 1.17K blocks/1.32M: accumulates), console.log (per-mode 200 attaches, 0 HAL_OK, 200 with ah_eeprom==NULL (orphaned mallocs) + balanced control + sizeof(HAL_EEPROM_v4k)=1152), build.log, env.txt, fix.diff",
  "kernel_refs": [
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c:311",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c:324",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c:366",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c:385",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c:390",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c:267",
    "sys/dev/netif/ath/ath_hal/ar9002/ar9285_attach.c:246",
    "sys/dev/netif/ath/ath_hal/ar5416/ar5416_attach.c:507",
    "sys/dev/netif/ath/ath_hal/ah_internal.h:474",
    "sys/dev/netif/ath/ath_hal/ah_osdep.c:121"
  ],
  "poc_changes": "Adapted from the DF-4913 v14 harness (KLD + sysctl hw.v4kleak=1 trigger, moduledata_t, -I/usr/obj/usr/src/sys/X86_64_GENERIC). Fixed one bring-up bug: control-path kprintf dropped its NFAIL argument (-Werror=format). v4k deltas: ah_eeprom_v4k.h include (owl_eep_start_loc 64), NWORDS from struct ar5416eeprom_4k (188 words/376B), error lines 324/366/385, control image version 0xE001 (AR5416_EEP_VER 0xE).",
  "attempts": 2,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 240,
  "guest_dirty": 1,
  "build_cmd": "cd /root/DF-4956 && make (KLD v4kleak.ko, cc 8.3 [DragonFly])",
  "run_cmd": "kldload ./v4kleak.ko && sysctl hw.v4kleak=1 && vmstat -m | grep -i ath_hal && kldunload v4kleak && vmstat -m | grep -i ath_hal",
  "code_hash": "3bbfef400952814e76f54ee54080e39a5cc9ef0f58eba7eed596b2f19e5e7b1a",
  "notes": "Leak is permanent and accumulates per attach round (600->1200 blocks). Same family/fix as DF-4873 (ar9287) and DF-4913 (v14); completes the family \u2014 every eeprom variant (v1 DF-1995, v4k DF-4956, v14 DF-4913, 9287 DF-4873) now has the attach-leak filed; v3 legacy and ar9300 use different shapes. ath_hal is compiled into the guest kernel, so the PoC needed no module load of the HAL itself.",
  "fix_status": "not_applicable",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Fix validation not performed: ath_hal is compiled into the guest kernel, so validating fix.diff requires a full kernel rebuild; the finding is a pure leak (no corruption) for which fix validation is not mandated. The PoC control path (valid image -> attach succeeds -> v4kEepromDetach frees) demonstrates the free path is balanced, and fix.diff (git apply --check clean) adds the same ath_hal_free(ee) on the three error returns.",
  "fix_evidence": "fix.diff mirrors the verified control-path lifetime (malloc at :311 <-> v4kEepromDetach free at :272); identical to the DF-4873/DF-4913 family fix.",
  "recommended_fix": "ath_hal_free(ee) before each of the three post-malloc error returns (HAL_EEREAD :324, HAL_EEBADSUM :366, HAL_EEBADSUM :385) \u2014 same fix as DF-4873/DF-4913."
}