β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2059

Missing privilege check on SIOCGATHDIAG/SIOCGATHPHYERR/SIOCGATHSPECTRAL exposes raw HAL diagnostic surface to unprivileged users

Summary

ath_ioctl dispatches HAL diag ioctls SIOCGATHDIAG/SIOCGATHPHYERR/SIOCGATHSPECTRAL with NO caps_priv_check_self -- contrast SIOCZATHSTATS at :288 caps_priv_check_self(SYSCAP_NODRIVER) and ieee80211_ioctl.c:3472 SIOCS80211 caps_priv_check_self(SYSCAP_NONET_WIFI). These ioctls fall into ieee80211_ioctl default: at 3516-3522 which calls ic->ic_ioctl with no priv test. Any local user with datagram socket reads/writes NIC registers (HAL_DIAG_SETREGS id 33 -> ath_hal_setregs writes arbitrary addr,value MMIO ah.c:893-894), reads EEPROM (HAL_DIAG_EEREAD id 17 -> arbitrary EEPROM word), dumps full EEPROM/registers/cached fatal state. Impact: change channel to restricted bands, raise TX power past regulatory (FCC/ETSI violation), change MAC, corrupt crypto state, wedge radio (DoS). Read EEPROM calibration/regdomain/MAC/register state. SIOCGATHNODERATESTATS leaks per-station rate/RSSI. This missing check is also precondition for F2 (invalid free) and F3 (OOB read) reachability by unprivileged. AV:L/PR:L/AC/L, C:H/I:H/A:H.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2059 Β· 7 files
FileTypeDescriptionSize
VERDICT.md verdict full narrative, mechanism, citations, fix-build result 4.0 KB ↓ raw
README.md readme evidence-pack overview 1.5 KB ↓ raw
fix.diff suggested-fix standalone git-apply-able fix (authored post-verification) 878 B view raw
build.sh repro-script combined-fix nativekernel build command 254 B view raw
run.sh repro-script runtime trigger (HW/module-gated) 379 B view raw
fix_build.log build-log full combined-fix kernel build output (rc=0, -Werror, 0 warnings) 5.6 MB ↓ download
env.txt environment guest uname / kern.version / cc version 289 B view raw
README.md readme evidence-pack overview
↓ download raw

DF-2059 β€” PoC evidence pack

Finding: Missing privilege check on SIOCGATHDIAG/SIOCGATHPHYERR/SIOCGATHSPECTRAL Class: Missing privilege / authorization (CWE-862) | Impact ceiling: none | Confidence: certain

Status

SOURCE-CONFIRMED. The defect is verified real by line-by-line tracing of the audited sys/ tree, but it is HW/module-gated: the audit guest lacks the required hardware/module (Atheros (ath) WLAN NIC must be present & attached (guest has only vtnet0)), so it cannot be triggered at runtime here. See VERDICT.md for the full mechanism and citations.

How to reproduce (on a guest that HAS the hardware)

  1. Ensure the gating precondition is met: Atheros (ath) WLAN NIC must be present & attached (guest has only vtnet0).
  2. Apply fix.diff to confirm the cited path changes; before the fix the cited code path exhibits the behaviour described in VERDICT.md.
  3. The original finding markdown describes the runtime trigger.

Build validation (Phase 8)

fix.diff applies cleanly to pristine source. All nine findings' fixes were built together; see VERDICT.md "Phase 8" and fix_build.log:

make -j6 nativekernel KERNCONF=X86_64_GENERIC   # rc=0, -Werror, 0 warnings

Files

  • VERDICT.md β€” full narrative, mechanism, citations, fix-build result
  • fix.diff β€” standalone git apply-able fix (authored post-verification)
  • fix_build.log β€” full combined-fix kernel build output (rc=0, -Werror)
  • env.txt β€” guest environment for this verification
  • manifest.json β€” machine-readable catalog
VERDICT.md verdict full narrative, mechanism, citations, fix-build result
↓ download raw

DF-2059 β€” VERDICT

Verdict: REPRODUCED (source-confirmed; HW/module-gated β€” not runtime-triggerable on this guest) Class: Missing privilege / authorization (CWE-862) Impact ceiling: none 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() dispatches SIOCGATHDIAG, SIOCGATHPHYERR (both under #ifdef ATH_DIAGAPI) and SIOCGATHSPECTRAL straight to the HAL diagnostic surface with NO caps_priv_check_self(), while the adjacent SIOCZATHSTATS case (:288) and the net80211 SIOCS80211 path (ieee80211_ioctl.c:3472) both gate on a capability. ieee80211_ioctl.c:3516-3523 default: forwards unknown ioctls to ic->ic_ioctl (=ath_ioctl) with no priv test, so an unprivileged user with a datagram socket reaches the raw HAL: HAL_DIAG_SETREGS writes arbitrary addr,value MMIO (ah.c:871-877), HAL_DIAG_EEREAD reads arbitrary EEPROM words (ah.c:901-907), and the full register/fatal-state dump is exposed. This missing check is also the unprivileged reachability gate for DF-2060 (invalid free) and DF-2061 (OOB read).

Gating precondition: Atheros (ath) WLAN NIC must be present & attached (guest has only vtnet0)

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 none 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)

Add caps_priv_check_self(SYSCAP_NONET_WIFI) to the SIOCGATHDIAG, SIOCGATHPHYERR and SIOCGATHSPECTRAL case branches in ath_ioctl() (if_ath_ioctl.c), returning the errno on failure, matching the radio-configuration privilege used for SIOCS80211.

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)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

COMPILE-VALIDATED, runtime not_testable. The fix applies cleanly (git apply --check) and was built into the combined nativekernel KERNCONF=X86_64_GENERIC build: === NK_DONE rc=0 === with cc ... -Werror on every translation unit and 0 warnings. Source-traced closure: the three diag ioctl cases now require caps_priv_check_self(SYSCAP_NONET_WIFI). Runtime A/B not possible because the PoC needs an Atheros NIC absent from this guest.

baseline (unpatched) if_ath_ioctl.c: SIOCGATHDIAG -> return(ath_ioctl_diag) (no check); patched (combined build): === NK_DONE rc=0 ===, 0 warnings in if_ath_ioctl.c. Gating: no ath NIC on guest => runtime not_testable.
↓ fix.diffcombined-fix kernel built rc=0 -Werror (kernel.stripped sha256 6086a989...); not booted β€” runtime not_testable (HW-gated: no Atheros NIC)

Confirmed kernel references

Detail

Exploit chain

none (authorization/CWE-862 defect, not a memory-corruption primitive). It is the unprivileged reachability gate that makes DF-2060 (invalid free) and DF-2061 (OOB read) reachable by an unprivileged user; those carry the corruption primitives but are themselves HW-gated (no ath NIC) on this guest.

Evidence (decisive lines)

if_ath_ioctl.c:299 SIOCGATHDIAG -> return(ath_ioctl_diag(sc,data)) with no priv check; :288 SIOCZATHSTATS has caps_priv_check_self(SYSCAP_NODRIVER); ieee80211_ioctl.c:3521 default: ic->ic_ioctl(ic,cmd,data) no priv test. Combined-fix kernel build: === NK_DONE rc=0 === (-Werror on every TU, 0 warnings).

PoC changes

findings/poc/DF-2059/ populated: VERDICT.md (full source trace + citations), fix.diff (adds caps_priv_check_self(SYSCAP_NONET_WIFI) to the three diag ioctl cases), README.md, build.sh, run.sh, env.txt, fix_build.log, manifest.json. Original PoC dir had only a placeholder README.

Verified recommended fix

In ath_ioctl() (if_ath_ioctl.c) add int error = caps_priv_check_self(SYSCAP_NONET_WIFI); if (error) return (error); to the SIOCGATHDIAG, SIOCGATHPHYERR and SIOCGATHSPECTRAL case branches, matching the radio-config privilege used for SIOCS80211. Standalone diff in findings/poc/DF-2059/fix.diff; supersedes finding proposal (the finding named the check but did not pin the capability β€” SYSCAP_NONET_WIFI is the correct radio-config capability).

Verdict

SOURCE-CONFIRMED (HW-gated, not runtime-triggerable on this guest). ath_ioctl() dispatches SIOCGATHDIAG/SIOCGATHPHYERR (if_ath_ioctl.c:299/301, under #ifdef ATH_DIAGAPI) and SIOCGATHSPECTRAL (:304) to the raw HAL diagnostic surface with NO caps_priv_check_self(), whereas the adjacent SIOCZATHSTATS case (:288) and the net80211 SIOCS80211 path (ieee80211_ioctl.c:3472) both gate on a capability. ieee80211_ioctl.c:3516-3523 default: forwards unknown ioctls to ic->ic_ioctl with no priv test, so an unprivileged socket reaches HAL_DIAG_SETREGS (write arbitrary addr/value MMIO), HAL_DIAG_EEREAD (read arbitrary EEPROM), and full register/fatal dumps. This missing check is also the unprivileged reachability gate for DF-2060 and DF-2061. Confirmed by line-by-line source trace; not runtime-triggerable because the guest has no Atheros NIC (only vtnet0).