{
  "finding_id": "DF-4913",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "Kernel heap memory leak (permanent, 4800 bytes per failed attach) on the v14 EEPROM-attach error paths of ath_hal_v14EepromAttach: the HAL_EEPROM_v14 mallocd at ah_eeprom_v14.c:363 is orphaned by three post-malloc returns \u2014 HAL_EEREAD at :376 (mid-image read failure), HAL_EEBADSUM at :414 (bad checksum) and :433 (bad version) \u2014 none of which free it, and AH_PRIVATE(ah)->ah_eeprom / ah_eepromDetach are installed only at :438-440 after every error return. The caller unwind (ar5416/ar9280/ar9160/ar9130 attach -> bad: -> ar5416Detach -> ath_hal_eepromDetach macro, ah_internal.h:474-478) is a no-op for it. Exact twin of DF-4873 (ar9287), which already predicted this file has the same family bug. Reproduced on the guest by calling the real in-kernel function with a synthetic ath_hal whose eepromRead callback serves crafted images: 3 failure modes x 200 attaches orphaned 600 blocks / 2.93MB of malloc type ath_hal (permanent across kldunload), while 200 valid attach+detach control cycles left inuse unchanged; a second run stacked to 1200 blocks / 5.86MB. Attacker model: untrusted EEPROM / hostile 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/2.93M, unchanged after kldunload; second run 1200/5.86M), console.log (per-mode 200 attaches, 0 HAL_OK, 200 with ah_eeprom==NULL (orphaned mallocs) + balanced control), build.log, env.txt, fix.diff",
  "kernel_refs": [
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v14.c:363",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v14.c:376",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v14.c:414",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v14.c:433",
    "sys/dev/netif/ath/ath_hal/ah_eeprom_v14.c:438",
    "sys/dev/netif/ath/ath_hal/ah_internal.h:474",
    "sys/dev/netif/ath/ath_hal/ar5416/ar5416_attach.c:373",
    "sys/dev/netif/ath/ath_hal/ar9002/ar9280_attach.c:256",
    "sys/dev/netif/ath/ath_hal/ah_osdep.c:118"
  ],
  "poc_changes": "Initial draft auto-ran the demo at MOD_LOAD and passed the handler function directly to DECLARE_MODULE(); DFly requires a moduledata_t struct (kern_linker.c casts md_data to moduledata_t* and dereferences ->name, which made the first loads GPF in module_register/strcmp). Fixed by declaring static moduledata_t v14leak_mod and moving the demo behind sysctl hw.v14leak=1; added -I/usr/obj/usr/src/sys/X86_64_GENERIC for generated kernel headers.",
  "attempts": 4,
  "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": 300,
  "guest_dirty": 1,
  "build_cmd": "cd /root/DF-4913 && make (KLD v14leak.ko, cc 8.3 [DragonFly])",
  "run_cmd": "kldload ./v14leak.ko && sysctl hw.v14leak=1 && vmstat -m | grep -i ath_hal && kldunload v14leak && vmstat -m | grep -i ath_hal",
  "code_hash": "83b798012d4cec79001817cc18f5d738bd31469cf2f6461d47fa14b786af6210",
  "notes": "Leak accumulates per attach round and is permanent (no back-reference to the orphaned block). Same family as DF-4873 (ar9287, just filed) and the v4k sibling. 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 control path of the PoC (valid image -> attach succeeds -> detach frees) demonstrates the free path is balanced, and fix.diff adds the same ath_hal_free(ee) on the three error returns.",
  "fix_evidence": "fix.diff mirrors the verified control-path lifetime (malloc at :363 <-> v14EepromDetach free at :318).",
  "recommended_fix": "ath_hal_free(ee) before each of the three post-malloc error returns (HAL_EEREAD :376, HAL_EEBADSUM :414, HAL_EEBADSUM :433) \u2014 same fix as DF-4873."
}