# DF-2060 — VERDICT

**Verdict:** REPRODUCED (source-confirmed; HW/module-gated — not runtime-triggerable on this guest)
**Class:** Free of memory not at start of buffer / invalid free (CWE-590)
**Impact ceiling:** panic
**Confidence:** certain

## Reproduction status

This finding is **HW/module-gated** and could not be triggered at runtime on the
audit guest. The guest has **no Atheros NIC, no AdvanSys HBA, no Intel i915 GPU,
no AMD Southern-Islands GPU, no LSI MegaRAID controller, and no loaded dm
device** (only `vtnet0`). The PoC therefore cannot reach the vulnerable path at
runtime here. The bug is instead **confirmed by line-by-line source tracing**
against the audited `sys/` tree (master DEV, the same commit the kernel was built
from) — the defect is real and deterministic *given the hardware/module*, which is
the standard bar for HW-gated driver findings.

## Mechanism (source-confirmed)

ath_ioctl_diag() allocates outdata via kmalloc(outsize,M_TEMP) when ATH_DIAG_DYN is set (:201), then passes &outdata to ath_hal_getdiagstate() (:214). For diagcode HAL_DIAG_REVS the HAL REPLACES *result with &AH_PRIVATE(ah)->ah_devid (ah.c:887) and for HAL_DIAG_FATALERR with &ah_fatalState[0] (ah.c:898) -- both interior pointers into the single kmalloc'd ath_hal struct. Cleanup at :232-233 does kfree(outdata,M_TEMP), freeing that interior/non-heap address -> slab panic (free of unallocated memory) or slab-metadata corruption on GENERIC (INVARIANTS). The original kmalloc buffer is also leaked. Trigger: ad_id=ATH_DIAG_DYN|HAL_DIAG_REVS or |HAL_DIAG_FATALERR.

**Gating precondition:** Atheros (ath) WLAN NIC present; ATH_DIAGAPI compiled in; reachability ungated only because of DF-2059

## Exploit chain

Not applicable — this finding is HW/module-gated on the audit guest (no
triggering hardware/module present), so no userspace-driven escalation chain can
be exercised here. Per AGENT.md Phase 6 the valid hard blocker that applies is
"vulnerable code path is reachable only on hardware/module absent from this
guest." The realistic impact ceiling for the bug itself is `panic` as
documented above (panic for the corruption-class bugs on default GENERIC with
INVARIANTS ON; dos for the I/O-wedge/stall bugs; none/graceful-fallback for the
validation-bypass and pure missing-check / resource-leak findings).

## Fix (authored, git-apply-able)

Track the original kmalloc'd result buffer in a separate `outbuf` pointer and free outbuf (not the HAL-replaced outdata) on the cleanup path in ath_ioctl_diag() (if_ath_ioctl.c). This fixes both the invalid free and the buffer leak.

The standalone diff is `fix.diff` in this directory. It applies cleanly to the
pristine audited source (`git apply --check` verified).

## Phase 8 — combined fix-build validation

All nine findings' fixes were applied together to a single in-guest source tree
and built with `make -j6 nativekernel KERNCONF=X86_64_GENERIC`. The DragonFly
kernel compile invokes `cc ... -Werror` on **every** translation unit, so this
is a true **-Werror** build.

- Result: **`=== NK_DONE rc=0 ===`** (full log: `fix_build.log`)
- Compiler errors in changed files: **0**
- Compiler warnings (entire tree): **0**
- Patched `kernel.stripped` sha256: `6086a989213ef7be890180f60edc0fd9827bf60efbc3ed8c969724746e250df6`
- Baseline (unpatched) kernel: `DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026`

Because the PoC is HW/module-gated, the fix could not be runtime A/B tested on
this guest (no way to trigger the bad behaviour on either the baseline or the
patched kernel). The fix is therefore classified **fix_status = not_testable**
(compile-validated + source-traced to close the cited path), which is the honest
result for HW-gated findings.

## Kernel references (verified during this trace)

- `sys/dev/netif/ath/ath/if_ath_ioctl.c:201`
- `sys/dev/netif/ath/ath/if_ath_ioctl.c:214`
- `sys/dev/netif/ath/ath/if_ath_ioctl.c:232`
- `sys/dev/netif/ath/ath_hal/ah.c:887`
- `sys/dev/netif/ath/ath_hal/ah.c:898`
