# DF-5030 — ar5312_attach.c: unvalidated BSP board-config pointer dereference in ar5312GetMacAddr **File:** `sys/dev/netif/ath/ath_hal/ar5312/ar5312_attach.c` **Severity:** Info (latent — file is not compiled into any standard build) **Confidence:** certain (code inspection + build-gating proof on the audit guest) ## What the code does `ar5312GetMacAddr()` (ar5312_attach.c:287-309) obtains the Wi-Fi MAC for the SoC WMAC unit by dereferencing two pointers that come from the HAL bus tag: ```c const struct ar531x_boarddata *board = AR5312_BOARDCONFIG(ah); int wlanNum = AR5312_UNIT(ah); ... macAddr = board->wlan0Mac; /* or board->wlan1Mac */ OS_MEMCPY(AH5212(ah)->ah_macaddr, macAddr, 6); ``` `AR5312_BOARDCONFIG`/`AR5312_UNIT` (ar5312/ar5312.h:25-30) simply cast `ah->ah_st` (the `HAL_BUS_TAG` argument the SoC BSP passed to attach) to `struct ar531x_config *` and load `->board` / `->unit`. There is **no NULL check, no `AR531X_BD_MAGIC` (0x35333131, ah_soc.h:35) validation, and no bounds check** anywhere between the BSP contract ("the driver is required to locate and fill-in this information", ah_soc.h:79-84) and the 6-byte copy into `ah_macaddr`. On a SoC build whose flash scan failed to find the "5311" magic (boarddata absent/corrupt — exactly the situation the magic constant exists to detect), the copy reads 6 bytes from a wild flash-derived address: at best a kernel panic on unmapped flash, at worst 6 bytes of arbitrary kernel/flash memory that then become the interface MAC and are readable by **any unprivileged user** via `ifconfig`/`getifaddrs`. ## Why it is only Info The file is dead code on every standard DragonFly build: * `sys/conf/files:153-232` lists the whole ath_hal (ar5210, ar5211, ar5212, ar5416, ar9001, ar9002, ar9300 contrib) — **no ar5312 entry**. * `sys/dev/netif/ath/ath_hal/Makefile` (kmod) SRCS — **no ar5312 path**. * `AH_SUPPORT_2316`/`AH_SUPPORT_2317` appear nowhere in the tree, so even a hand-wired build compiles out ar5312_attach.c:101-109/134-146. * `AH_CHIP(AR5312, ...)` (ar5312_attach.c:335) never registers, so `ar5312Probe`/`ar5312Attach` are unreachable even inside a loaded ath_hal. * Verified on the audit guest (reachability.log): 0 ar5312 references in `sys/conf/files`, 0 in the kmod Makefile, **0 ar5312 symbols in the shipped `ath_hal.ko` and in the static `kernel`**. The remaining latent nits found in the same file (recorded, not filed): duplicated `AR_SREV_VERSION_VENICE` term in the unsupported-chip check (ar5312_attach.c:157-160, upstream FreeBSD "XXX THIS IS WRONG" quirk, fails closed); dead stores at ar5312_attach.c:149-150; `(uint32_t)sh` truncation in the RSTIMER reads (ar5312_attach.c:139,149-152) which is only valid for the 32-bit SoC bus layout. The `bad:` unwind was audited and is sound: `ar5212InitState` (line 85) sets the magic before any failure, and `ar5212RfDetach` NULL-guards `ah_rfHal` (ar5212/ar5212.h:403-406), so no double-free/UAF on any error path. ## Reproduce (reachability, read-only) See `reachability.sh` / `reachability.log` — run on the QEMU guest via `dfbsd-qemu/vm.sh run_root`. No PoC exists because the code cannot be reached at runtime on this (or any standard) build. ## Recommended fix Validate the BSP-supplied pointer before use (one-line defense-in-depth): ```diff --- a/sys/dev/netif/ath/ath_hal/ar5312/ar5312_attach.c +++ b/sys/dev/netif/ath/ath_hal/ar5312/ar5312_attach.c @@ -286,7 +286,12 @@ static HAL_BOOL ar5312GetMacAddr(struct ath_hal *ah) { const struct ar531x_boarddata *board = AR5312_BOARDCONFIG(ah); - int wlanNum = AR5312_UNIT(ah); + const struct ar531x_config *config; + int wlanNum; const uint8_t *macAddr; + + if ((config = (const struct ar531x_config *) ah->ah_st) == AH_NULL || + (board = config->board) == AH_NULL || + board->magic != AR531X_BD_MAGIC) + return AH_FALSE; + wlanNum = config->unit; ``` (Full context in `fix.diff`; never applied to `sys/`.)