⬢ DragonFlyBSD Kernel Audit
DF-5070 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5070",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Sink-level reproduction on the stock guest kernel (DF-4986/DF-5012/DF-5024 house precedent): a KLD carrying the verbatim ath_ioctl_spectral() control flow (copyin-flag logic + SET_PARAMS/ENABLE_AT_RESET arms, if_ath_spectral.c:184/197/233-238/255-273) proves that SPECTRAL_CONTROL_SET_PARAMS with ad_in_size >= sizeof(HAL_SPECTRAL_PARAM)=36 but WITHOUT the ATH_DIAG_IN flag passes the :233 size check with indata still NULL, and the HAL call (replicated as ar5416ConfigureSpectralScans first field accesses, ar5416_spectral.c:92/:97 read + :143->:157-167 write) faults: Fatal trap 12, supervisor read, fault va 0x2 (NULL + offsetof(ss_period)), stopped at df5070_ioctl+0x110. Controls in the same run: the same ioctl WITH the flag succeeds (rc=0, hal_configure touched the params safely), and the sibling ENABLE_AT_RESET arm with no flag is REJECTED EINVAL by its explicit indata==NULL check (if_ath_spectral.c:263-267) -- the asymmetry that proves the missing check is an oversight (dfs_null twin already filed as DF-2052). Unprivileged reachability rides DF-2081 (SIOCGATHSPECTRAL dispatched with no priv check via ieee80211_ioctl.c:3516-3523 -> if_ath_ioctl.c:304-305; halSpectralScanSupport on AR9280/85/87). The real entry is HW-gated on this guest (no Atheros NIC); the control flow, sizes and dereference are source-exact. Exploit ceiling: fixed-offset NULL READ on an unmappable page -- reliable unprivileged panic/DoS, no corruption primitive (the corruption-class issue in this function is the known DF-2079, a different arm). Fix A/B: with the single indata==NULL check added to SET_PARAMS, the same call returns EINVAL and the guest stays up; fix.diff also compile-validated against the guests /usr/src (if_ath.ko with patched if_ath_spectral.o, -Werror clean; sources restored).",
  "exploit_chain": "",
  "evidence": "panic.txt: Fatal trap 12: page fault while in kernel mode / fault virtual address = 0x2 / Stopped at df5070_ioctl+0x110: movzwl 0x2(%r14),%ecx (preceded by the control runs hal_configure(ah, ss=0xfffff8008976ba40): reading ss_fft_period=65535 and the contrast arms ENABLE_AT_RESET: indata=NULL); run.log: control rc=0, contrast errno=22, fire -> ssh session killed by the panic; run_fixed_ab.log: fire: ... ad_in_size=64 -> ioctl rc=-1 errno=22 + dmesg df5070f: SET_PARAMS rejected: indata == NULL (ATH_DIAG_IN not set) + uptime alive; fix_validation.log: if_ath.ko built -Werror clean from patched /usr/src/sys/dev/netif/ath/ath",
  "kernel_refs": [
    "sys/dev/netif/ath/ath/if_ath_spectral.c:233",
    "sys/dev/netif/ath/ath/if_ath_spectral.c:237",
    "sys/dev/netif/ath/ath/if_ath_spectral.c:238",
    "sys/dev/netif/ath/ath/if_ath_spectral.c:197",
    "sys/dev/netif/ath/ath/if_ath_spectral.c:263",
    "sys/dev/netif/ath/ath/if_athioctl.h:183",
    "sys/dev/netif/ath/ath_hal/ar5416/ar5416_spectral.c:92",
    "sys/dev/netif/ath/ath_hal/ar5416/ar5416_spectral.c:143",
    "sys/dev/netif/ath/ath_hal/ar5416/ar5416_spectral.c:157",
    "sys/netproto/802_11/wlan/ieee80211_ioctl.c:3516",
    "sys/dev/netif/ath/ath/if_ath_ioctl.c:304",
    "sys/dev/netif/ath/ath_hal/ar9002/ar9280_attach.c:904"
  ],
  "poc_changes": "authored fresh from source analysis (no seed); sink KLD per DF-4986/DF-5024 precedent because the guest has no spectral-capable Atheros NIC; fixed variant built as a #define wrapper (df5070_fixed.c) after discovering DFlys bsd.kmod.mk silently drops ad-hoc CFLAGS (first fixed .ko was byte-identical to baseline)",
  "attempts": 3,
  "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": 540,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh (make KMOD df5070 + df5070f + cc df5070_trigger.c) on the guest",
  "run_cmd": "sh run.sh (control/contrast/fire -> panic; capture via vm.sh log; then vm.sh reset with-src); sh run_fixed_ab.sh (fire -> EINVAL, no panic); patch -p1 + make in /usr/src/sys/dev/netif/ath/ath (fix_validation.log)",
  "code_hash": "ae2c608276f19398a979a9ba0fc6db20f89f60e6bbceaabc79ac664e3e5c30e1",
  "notes": "Pass-2 finding on sys/dev/netif/ath/ath/if_ath_spectral.c; the known DF-2079/DF-2080/DF-2081 and the DF-5024 error-path-copyout shape (subsumed by DF-2080s unconditional-copyout root cause at if_ath_spectral.c:282-285) were NOT re-exercised. sizeof(HAL_SPECTRAL_PARAM)=36 confirmed from both sides at runtime. Also noted in audit: ar5416PrepSpectralScan DISABLES radar detection (ar5416_spectral.c:48-73) -- a regulatory/RF concern that folds into DF-2081s unprivileged-radio-config threat, not filed separately.",
  "recommended_fix": "if_ath_spectral.c SPECTRAL_CONTROL_SET_PARAMS: reject when indata == NULL (ATH_DIAG_IN not set), mirroring the ENABLE_AT_RESET check at :263-267 (fix.diff, compile-validated).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Behavioral A/B at sink level (run_fixed_ab.log): baseline control flow panics (Fatal trap 12, va 0x2); fixed variant (identical module + the single indata==NULL check in SET_PARAMS) returns EINVAL for the same call with the guest alive and the control/contrast arms unchanged. fix.diff also applied to the guests /usr/src and compile-validated: if_ath.ko built -Werror clean including the patched if_ath_spectral.o (fix_validation.log; sources restored pristine). The real ath entry is HW-gated on this guest; the failure mode and its removal are properties of the driver-side control flow.",
  "fix_evidence": "run_fixed_ab.log (fire: ... errno=22 + df5070f: SET_PARAMS rejected: indata == NULL + uptime); fix_validation.log (patched if_ath.ko -Werror clean); fix.diff"
}