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

Unsupported 5GHz radio-revision check fails open: the HAL_ENOTSUPP/goto bad rejection is compiled out unless AH_DEBUG β€” ar9160/DF-5023 family twin, shipped fail-open empirically confirmed

Summary

The rejection sits inside #ifdef AH_DEBUG - stock builds attach anyway and drive the unsupported radio with ar9130.ini banks. Shipped fail-open PROVEN from the guest binary: ath_hal.ko contains ar9130Attach but zero occurrences of the rejection string. Hardware-gated dead on x86 (apb bus has no driver; devid 0x000b is SoC-only); all 10 ini counts verified, unwind sound, v14 leak is DF-4913. Un-#ifdef-the-rejection fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5038 Β· 9 files
FileTypeDescriptionSize
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 4.7 KB ↓ raw
gating_check.sh β€” 1.5 KB view raw
run.sh β€” 240 B view raw
run.log β€” 763 B view raw
env.txt β€” 256 B view raw
fix.diff β€” 469 B view raw
manifest.json β€” 1.3 KB view raw
verdict.json β€” 3.6 KB view raw

DF-5038 β€” ar9130 radio-rev rejection compiled out without AH_DEBUG (fail-open)

File: sys/dev/netif/ath/ath_hal/ar9001/ar9130_attach.c:197-215 Class: Fail-open input validation (family twin of DF-5023, ar9160; same directory, same inherited Atheros pattern) Severity: Info β€” hardware-gated (AR9130 SoC only), no attacker-controlled input reaches it on any supported platform.

What this pack proves (and does not)

There is no runtime PoC for this finding: the rejected input (ah_analog5GhzRev) is read from AR9130 SoC silicon registers (ar5416GetRadioRev, ar9130_attach.c:196), and the only caller is the apb-bus front-end if_ath_ahb.c β€” a bus with no driver anywhere in the x86 tree and no hardware inside the QEMU guest. Runtime reproduction requires physical AR9130 (Howl) MIPS hardware that neither this audit nor the guest has.

What is verified, empirically and read-only on the guest:

  1. Build gating: ar9130Attach/ar9130Probe are compiled into the shipped /boot/kernel/ath_hal.ko (module not loaded β€” no ath hardware present).
  2. The fail-open ships: the rejection string "5G Radio Chip Rev ... not supported by this driver" (inside the #ifdef AH_DEBUG block, ar9130_attach.c:207-211) is absent from the shipped ath_hal.ko β€” proof that AH_DEBUG was not defined at build time, i.e. the ecode = HAL_ENOTSUPP; goto bad; lines were compiled out and the shipped attach fails open on an unsupported radio revision.
  3. No apb bus / 0x000b PCI device exists on the guest (reachability = 0).

How to reproduce the gating proof

# guest up (dfbsd-qemu/vm.sh status), then from repo root:
sh findings/poc/DF-5038/run.sh          # prints the three sections above

Expected: the two symbol lines under section 1; 0 for both string counts in section 2; 0 0 in section 3. Full output: run.log.

VERDICT.md
↓ download raw

DF-5038 β€” VERDICT

Finding: AR9130 HAL attach rejects an unsupported 5 GHz radio revision only inside #ifdef AH_DEBUG; in stock builds the rejection does not exist and the attach proceeds with an unsupported radio (fail-open).

Root cause (path:line)

sys/dev/netif/ath/ath_hal/ar9001/ar9130_attach.c:196-215:

AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah);
switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */
case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */
        break;
default:
        if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) {
                AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR;
                break;
        }
#ifdef AH_DEBUG                                   /* <-- line 207 */
        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not "
            "supported by this driver\n", ...);
        ecode = HAL_ENOTSUPP;
        goto bad;                                  /* <-- compiled out */
#endif
}
rfStatus = ar2133RfAttach(ah, &ecode);             /* line 216: continues anyway */

With AH_DEBUG undefined β€” the shipping configuration β€” the default: arm falls straight through the (empty) #ifdef and execution continues at ar2133RfAttach() on a part whose radio revision the HAL explicitly does not claim to support. The subsequent RF programming (ar9130.ini banks via HAL_INI_INIT at ar9130_attach.c:161-167) assumes the supported radios, so an out-of-revision radio would be driven with wrong calibration/board data β€” the classic "mis-tuned radio / out-of-spec transmission" hazard this check exists to prevent. This is byte-for-byte the same pattern as ar9160 (DF-5023, ar9160_attach.c:222-240), inherited from the FreeBSD/Atheros HAL.

Verification actually performed

  • Code traced line-by-line: switch arms, the rev==0 β†’ force 5133 alias (a legitimate quirk for unreadable rev), the #ifdef, and the fall-through into ar2133RfAttach at ar9130_attach.c:216.
  • AH_DEBUG build default confirmed: nothing in sys/dev/netif/ath/ath_hal/Makefile, sys/conf/files, or the module machinery defines AH_DEBUG; HALDEBUG() itself is a do { } while (0) no-op without it (ah_internal.h:649-651).
  • Empirical, on the guest (read-only): strings /boot/kernel/ath_hal.ko contains zero occurrences of "5G Radio Chip Rev" / "not supported by this driver" while nm shows ar9130Attach/ar9130Probe present β€” the module containing the code was built without the rejection. See run.log.
  • Reachability: ar9130Attach is reached only via ah.c:ath_hal_attach (linker-set ah_chips, ah.c:64-72) with devid 0x000b (ah_devid.h:77), which only if_ath_ahb.c:109,290 supplies β€” the apb bus front-end. No apb bus driver exists anywhere in the x86 tree (grep over sys/ finds none; kldstat -v | grep -ci apb = 0 on the guest), and AR5416_AR9130_DEVID is a SoC devid that does not exist as PCI silicon. So the code ships compiled-in but is callable only on AR9130 MIPS hardware DragonFly does not run on.

Why not reproduced (honest classification)

The gating input is silicon state, not user input; there is no syscall, ioctl, or packet path to it. The QEMU guest has no AR9130, no apb bus, and no ath device (kldstat shows ath_hal.ko not even loaded). Producing the fail-open would require physically desoldering/mis-reporting silicon on a Howl SoC. Status is therefore untested (runtime), with the fail-open itself certain by inspection + shipped-binary proof.

Impact assessment

  • Attacker control: none (silicon-provided value). Not reachable on x86 or from any unprivileged/remote position on any supported platform.
  • Worst realistic effect (on hypothetical AR9130 hardware with an unexpected radio rev): attach succeeds where it must fail; RF banks programmed for a different radio β†’ mis-calibrated transmissions, regulatory-domain uncertainty. Defense-in-depth failure only. Info, matching the family precedent (DF-5023 Info, ar9160).

Fix

Move the rejection out of #ifdef AH_DEBUG (keep the debug print as a no-op HALDEBUG β€” it compiles away in stock builds). See fix.diff. Fix NOT validated on hardware (none exists); the change is a two-line de-ifdef and cannot regress the supported-rev paths (they break before it).

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_testable
baseline no→ patch + rebuild →patched clean

fix.diff (two-line de-ifdef) applies cleanly to sys/ via git apply --check; behavior change is compile-time-only and unconditional on the unsupported-rev path, so no supported-rev path can regress. Not kernel-built/hardware-validated: no AR9130 hardware exists in the audit environment (fix validation mandated only for reproduced memory-corruption findings).

fix.diff; 'CLEAN APPLY' from git apply --check recorded in this pack; no baseline run exists to compare (see verdict).
↓ fix.diffper-fix-DF-5038

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log section 2: 'not supported by this driver' / '5G Radio Chip Rev' string counts are 0 in the shipped ath_hal.ko while nm shows ar9130Attach/ar9130Probe (section 1) - the #ifdef AH_DEBUG rejection at ar9130_attach.c:207-214 was not compiled. VERDICT.md walks the fall-through at ar9130_attach.c:196-216 line by line. fix.diff de-ifdefs the rejection and applies cleanly (git apply --check).

PoC changes

No seed PoC existed; authored gating_check.sh (read-only guest script) + run.sh to prove build gating and the AH_DEBUG-off fail-open on the shipped binaries instead, since runtime triggering requires unavailable AR9130 silicon.

Verified recommended fix

Un-#ifdef the HAL_ENOTSUPP/goto-bad rejection at ar9130_attach.c:207-214 (keep HALDEBUG; it no-ops in stock builds) so unsupported radio revisions fail closed.

Verdict

Radio-revision rejection in ar9130Attach is compiled out unless AH_DEBUG is defined: in the shipping build (verified empirically - the rejection string is absent from the guest's /boot/kernel/ath_hal.ko while ar9130Attach is present) the default switch arm falls through and attach proceeds with an unsupported 5GHz radio rev, programming ar9130.ini RF banks calibrated for a different radio. Fail-open is certain by inspection and shipped-binary proof; runtime reproduction is impossible without AR9130 (Howl) MIPS SoC hardware - the only caller (if_ath_ahb.c) sits on the apb bus, which has no driver anywhere in the x86 tree and no device in the QEMU guest. Family twin of DF-5023 (ar9160, same pattern, same directory). Hardware-gated, no attacker-controlled input, hence Info and untested at runtime by design, not by omission.