# DF-4320 — Missing privilege check on SIOCGATHDIAG exposes the full HAL diagnostic interface (arbitrary device MMIO read/write, 802.11 keycache disclosure, NULL-deref panics)

## Build

```
cc -O2 -Wall -o poc poc.c
```

(Any DragonFly host; plain POSIX userland, no privileges needed.)

## Run

```
./poc            # probes every interface with SIOCGATHDIAG as the invoking user
```

## Expected

* **Vulnerable system** (kernel built with `options ATH_DIAGAPI`, an
  ath(4) wlan interface present, run as a plain user): prints
  `SETREGS  : SUCCESS` (an arbitrary device register write was accepted
  from an unprivileged uid) and/or `REGS-dump: SUCCESS` (device register
  dump, including the WEP/TKIP keycache registers at 0x9800+, handed to
  an unprivileged uid). No `EPERM` is ever produced — the DragonFly
  source has no privilege gate anywhere on the dispatch path
  (socket → `ifioctl` default → `ieee80211_ioctl` default →
  `ath_ioctl` case SIOCGATHDIAG → `ath_ioctl_diag`).
* **Stock X86_64_GENERIC** (no `ATH_DIAGAPI`): every probe returns
  ENOTTY/EINVAL — the ioctl case is not compiled into the kernel
  (verified: `nm /boot/kernel/if_ath.ko | grep ath_ioctl_diag` → empty).
  On the audit QEMU guest additionally no Atheros NIC exists
  (virtio-only PCI bus), so the wlan dispatch is never reached.

## Static proof (decisive on any host)

* `sys/dev/netif/ath/ath/if_ath_ioctl.c:288` — the neighboring ioctl
  SIOCZATHSTATS *does* check `caps_priv_check_self(SYSCAP_NODRIVER)`.
* `sys/dev/netif/ath/ath/if_ath_ioctl.c:299-302` — SIOCGATHDIAG /
  SIOCGATHPHYERR call `ath_ioctl_diag`/`ath_ioctl_phyerr` directly with
  **no** check. FreeBSD upstream gates the identical cases with
  `priv_check(curthread, PRIV_DRIVER)`.
* `sys/netproto/802_11/wlan/ieee80211_ioctl.c:3516-3520` — unknown
  ioctls are passed to the driver ("Pass unknown ioctls first to the
  driver") with no privilege check.
* `sys/dev/netif/ath/ath_hal/ah.c:878-935` — what the gate would be
  protecting: `HAL_DIAG_SETREGS` (arbitrary `addr,value` MMIO writes,
  unconditional), `HAL_DIAG_REGS` (arbitrary register-range dump —
  includes keycache), `HAL_DIAG_EEREAD`, plus (under AH_PRIVATE_DIAG)
  SETKEY/RESETKEY/EEWRITE.

## Files

* `poc.c` — the probe (struct layouts mirrored 1:1 from `if_athioctl.h`).
* `run.log` — guest run (default kernel: ENOTTY/EINVAL as predicted).
* `static_check.log` — guest kernel/module symbol + PCI evidence.
* `env.txt` — guest environment.
* `fix.diff` — the one-hunk fix.
