DF-4686 / verdict.json
{ "finding_id": "DF-4686", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "REPRODUCED on the DragonFly guest (verbatim-extraction harness, modes 4 and 5) -- the ar2425 twin of DF-4683 with an ar2425-specific twist: ar2425.c keeps VpdTable_L/R/I + Pmin_t2/Pmax_t2 as FUNCTION-SCOPE STATICS (ar2425.c:367-379), not struct members like the ar2317/ar2316/ar2413/ar5413 twins, so the span overflow marches through KERNEL STATIC STORAGE (adjacent .bss symbols), not a heap object. Neither ar2425FillVpdTables loop (bound = (uint16_t)(Pmax-Pmin) at ar2425.c:311, store at :325) nor the interpolate loop (:419-424) clamps the span to the 64-wide row or rejects Pmax<Pmin. (Mode 4) a DESCENDING pwr_t4 curve yields Pmax_t2=84 < Pmin_t2=90 (the :398-408 min() across idxL/idxR performs no monotonicity check), the bound wraps to 65530 -> 131060 bytes of uint16 stores from VpdTable_L[0][0] through the whole 1552-byte statics block and off its end; the harness faulted on the STORE at exactly the block end (guard page, exact match). (Mode 5) a VALID ascending curve spanning 102 half-dB needs no wrap: FillVpdTable spills rows L[3]/R[3][64..] into neighboring statics, and the interpolate loop writes VpdTable_I[3][0..101]; I[3][64] lands on Pmin_t2 (kernel: adjacent .bss), clobbers the loops own re-evaluated bound to a uint16-wrapped ~65535 and the march continues off the block end (fault exact-match). Values written are EEPROM-Vpd-derived. REACHABILITY (honest, refines DF-4683s framing): through the ONLY constructor (readEepromRawPowerCalInfo2413 -> ar2413EepromToRawDataset, ah_eeprom_v3.c:703-747) pwr deltas are UNSIGNED 4-bit fields (dbm_delta_mask=0xF, ah_eeprom_v3.c:450) summed cumulatively, so every pier curve is provably non-descending with span <= 4x15=60 half-dB: neither variant is constructible from EEPROM bits TODAY -- the missing clamp is latent/defense-in-depth (any decoder change, a divergent caller, or an eeprom v>5 re-arm it). Filed as the family twin DF-4683 explicitly flagged at ar2425.c:311. Fix validated: fixD (reject inverted/oversized spans) alone completes mode 5; mode 4 completes with fixD+fixB (skipping the inverted gain leaves zero gains -- DF-4688s early return covers the residual).", "exploit_chain": "crafted-EEPROM AR2425 card -> ath attach -> ar2425SetPowerTable (channel set/reset) -> ar2425getGainBoundariesAndPdadcsForPowers -> OOB write/wild read; ceiling radio misprogramming/panic (DoS), not uid0", "evidence": "run.log: mode 4 ... si_addr is 1552 bytes past block start (sizeof=1552) ... MATCH and mode 5 ... MATCH; fix_run.log: PATCHED mode 5 with fixD only ... no SIGSEGV and PATCHED mode 4 with fixB+fixD ... no SIGSEGV.", "kernel_refs": [ "sys/dev/netif/ath/ath_hal/ar5212/ar2425.c:311", "sys/dev/netif/ath/ath_hal/ar5212/ar2425.c:325", "sys/dev/netif/ath/ath_hal/ar5212/ar2425.c:419", "sys/dev/netif/ath/ath_hal/ar5212/ar2425.c:367", "sys/dev/netif/ath/ath_hal/ar5212/ar2425.c:373", "sys/dev/netif/ath/ath_hal/ah_eeprom_v3.h:291", "sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:450", "sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:703" ], "poc_changes": "ar2425-specific harness (vs DF-4680 template): the 5 function-scope static declarations (ar2425.c:367-379) are stripped from the verbatim extraction (asserted count) and re-bound to a guarded mmap block emulating kernel static storage -- ar2425 keeps the VpdTable/Pmin/Pmax scratch in .bss, not in ar2425State like the family twins; first build attempt had a macro/field name collision (offsetof) fixed by m_-prefixing the emulation fields; guest tar transfer ordering bug fixed (extract before overwrite)", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 90, "guest_dirty": 0, "build_cmd": "cd /root/df2425 && sh build.sh", "run_cmd": "cd /root/df2425 && sh run.sh", "code_hash": "636b2f3246c5e050c9c9e816348aa7314701607074df491027ffb367edd7c101", "notes": "hardware-gated (no AR2425 NIC on guest); verbatim-extraction methodology identical to accepted siblings DF-4619/4620/4622/4648/4649/4650/4660/4661/4662/4680/4681/4682/4683", "recommended_fix": "Reject inverted (Pmax<Pmin) or oversized (span >= MAX_PWR_RANGE_IN_HALF_DB) pd-gain curves before FillVpdTable (fixD; pair with fixB for the zero-gain residual).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Harness-level validation (fix_validate.sh): baseline modes 4/5 fault at the statics-block guard on the unpatched build; with fixD applied, mode 5 completes; mode 4 completes with fixD+fixB (residual zero-gain path after skipping the inverted gain). No kernel rebuild: no AR2425 hardware on the guest, the fix is validated against the verbatim-extracted function bodies per the family methodology (DF-4619..DF-4683).", "fix_evidence": "run.log: mode 4 ... si_addr is 1552 bytes past block start (sizeof=1552) ... MATCH and mode 5 ... MATCH; fix_run.log: PATCHED mode 5 with fixD only ... no SIGSEGV and PATCHED mode 4 with fixB+fixD ... no SIGSEGV." } |