ar5312GetMacAddr dereferences unvalidated BSP board-config pointer; 6-byte wild read becomes the unprivileged-readable Wi-Fi MAC on a SoC build with corrupt flash board-data
Summary
The BOARDCONFIG cast blindly loads ->board and OS_MEMCPYs 6 bytes from board->wlanXMac with no NULL check, no AR531X_BD_MAGIC validation, no bounds - the exact condition the magic detects. Purely latent: the file is in NO standard build (conf/files + ath_hal Makefile both lack it; guest-verified 0 ar5312 symbols in ath_hal.ko and kernel). Validate-the-BSP-config fix authored for the day it gets wired up.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5030 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.9 KB | β raw | |
| VERDICT.md | β | 3.3 KB | β raw | |
| reachability.sh | β | 995 B | view raw | |
| reachability.log | β | 290 B | view raw | |
| fix.diff | β | 887 B | view raw | |
| manifest.json | β | 1018 B | view raw | |
| verdict.json | β | 3.0 KB | view raw | |
| env.txt | β | 150 B | view raw |
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:
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-232lists 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_2317appear 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, soar5312Probe/ar5312Attachare 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 shippedath_hal.koand in the statickernel.
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):
--- 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/.)
DF-5030 VERDICT β untested (Phase V skipped: Info-severity latent finding)
Bottom line
ar5312GetMacAddr() (sys/dev/netif/ath/ath_hal/ar5312/ar5312_attach.c:287-309)
copies 6 bytes from ((struct ar531x_config *)ah->ah_st)->board->wlanXMac
with no NULL check, no AR531X_BD_MAGIC validation, no bounds check β a
genuine validation gap that on a MIPS AR5312/AR231x SoC build with missing or
corrupt flash board-data turns into a wild-pointer kernel read whose result
(the interface MAC) is exposed to unprivileged users via ifconfig, or a
panic. It is not exploitable on any standard DragonFly build because the
file is not compiled at all β proven three ways (sys/conf/files,
ath_hal kmod Makefile, and 0 ar5312 symbols in the shipped ath_hal.ko and
static kernel on the audit guest β see reachability.log).
Why no runtime PoC (status untested, not not_reproduced)
The trigger requires (a) a kernel built with the ar5312 HAL wired in (no build target does this today) and (b) AR5312-class SoC hardware with attacker-influenced flash. The audit guest is x86_64 with the standard X86_64_GENERIC kernel; the cited path is dead at build time, so there is nothing to run. This is a code-inspection finding with certain confidence about the code, zero runtime exposure.
Evidence
reachability.logβ guest output:conf-files-ar5312-count: 0,hal-makefile-ar5312-count: 0,symbols-ar5312-in-ath_hal.ko: 0,symbols-ar5312-in-kernel: 0.- Source: ar5312_attach.c:287-309 (the deref+copy), ar5312/ar5312.h:25-30
(the unchecked casts), ah_soc.h:33-35 (
AR531X_BD_MAGICdefined, never checked here), ah_soc.h:79-90 (the BSP contract the HAL trusts blindly).
Other classes checked and killed in this file (pass 2)
- EEPROM/flash map OOB β not in this file (ar5312_eeprom.c); attach-side
reads go through
ar5312EepromReadindirection only. - Ini table counts (ar5312_attach.c:125-126) β compile-time tables from ar5212.ini; HAL_INI machinery iterates fixed row/col counts; no attacker-controlled length.
- ANI params (ar5312_attach.c:36-57) β arrays sized 5/3/3 vs max levels 4/2/2; ar5212_ani.c guards every level index (ar5212_ani.c:240,313,331).
- Error unwind UAF/double-free β
bad:path (278-283) is safe: magic set byar5212InitState(85) before any failure;ar5212RfDetachNULL-guardsah_rfHal(ar5212.h:403-406);ath_hal_freecalled exactly once. - devid table sentinel β
AH_CHIP(ah_internal.h:97-104) linker-set registration; probe table is a complete switch with defaultAH_NULLreturn (311-334); no fallthrough. - Duplicated VENICE condition (157-160) β upstream logic typo, fails closed (attach rejected), no security impact. Dead stores (149-150), cosmetic.
Fix validation
Not performed β there is no reproducible baseline behavior to validate
against (dead code). fix.diff is the reviewer-authored defense-in-depth
patch (NULL + magic validation), untested at runtime by construction.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testableFix validation not applicable: Info-severity latent finding, no runtime baseline exists on the guest (file not compiled), Phase V skipped per contract.
n/a (no fix build performed)
Confirmed kernel references
Detail
Evidence (decisive lines)
reachability.log (guest: conf-files-ar5312-count 0, hal-makefile-ar5312-count 0, symbols-ar5312-in-ath_hal.ko 0, symbols-ar5312-in-kernel 0); ar5312_attach.c:287-309; ar5312/ar5312.h:25-30; ah_soc.h:33-35,79-90; sys/conf/files:153-232; VERDICT.md
PoC changes
No PoC built: the cited path is not compiled into the shipped ath_hal.ko or kernel (proven read-only on the guest). A reachability probe script (reachability.sh) replaces the trigger.
Verified recommended fix
Validate the BSP-supplied ar531x_config in ar5312GetMacAddr: reject NULL config/board and board->magic != AR531X_BD_MAGIC before the 6-byte copy (fix.diff).
Verdict
ar5312GetMacAddr (sys/dev/netif/ath/ath_hal/ar5312/ar5312_attach.c:287-309) dereferences the BSP-supplied ah_st as struct ar531x_config* and copies 6 bytes from board->wlanXMac with no NULL check and no AR531X_BD_MAGIC validation; on a MIPS SoC build with missing/corrupt flash board-data this is a wild-pointer kernel read (panic, or 6 bytes of kernel/flash memory exposed as the unprivileged-readable Wi-Fi MAC). However, the file is not compiled into any standard DragonFly build: sys/conf/files and the ath_hal kmod Makefile contain no ar5312 entry, AH_SUPPORT_2316/2317 are defined nowhere, and the shipped ath_hal.ko and static kernel on the audit guest contain zero ar5312 symbols. Info-severity latent defect; Phase V runtime PoC skipped per contract (code unreachable at build time).
No comments yet.