Wild OOB heap write in eepromExpandPower5112(): 0xDEAD sentinel xgainList[0] used as pDataPerXPD[] index when device EEPROM xpdMask has no set bits
Summary
For 5112-layout EEPROMs readEepromRawPowerCalInfo5112 passes ee_xgain[mode] (a 4-bit EEPROM nibble) as xpdMask with no zero check. The expand seeds xgainList with 0xDEAD sentinels and only guards 'too many' gains, never 'none'. With xpdMask==0 and >=1 cal pier, xgainList[0] stays 0xDEAD (57005) and is used as the index into pDataPerXPD[4] - 18 semi-controlled EEPROM-chosen bytes written at ~1.09 MiB past a ~92-byte block, repeated per pier at an 84-byte stride. DF-1447's sibling on the eepMap==1 path, but a wild WRITE instead of a static-table OOB read. HARNESS-PROVEN: verbatim function extraction over a 4MiB canaried arena - 'damaged bytes past allocation: 18 (first at +1140106)', EEPROM-chosen hexdump, numChannels=3 -> 54 bytes; fix.diff -> AH_FALSE, 0 damaged. Attacker model: control of the NIC EEPROM (malicious mini-PCIe card). kk==0 guard fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4207 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger.c | β | 6.1 KB | view raw | |
| build.sh | β | 92 B | view raw | |
| run.sh | β | 116 B | view raw | |
| fix.diff | β | 712 B | view raw | |
| build.log | β | 892 B | view raw | |
| run.log | β | 1.5 KB | view raw | |
| env.txt | β | 188 B | view raw | |
| verdict.json | β | 3.8 KB | view raw |
Fix verification
fixedfix.diff (kk==0 guard) applied to the verbatim extraction: eepromExpandPower5112 returns AH_FALSE, 0 canary-damaged bytes, exit 0 β wild write eliminated. git apply --check clean against sys/; never applied to the read-only tree.
run.log '===== with fix.diff applied =====' section: 'damaged bytes past allocation: 0' both runs, 'PASS: wild OOB write was NOT observed', 'RESULT: bug reproduced on stock, GONE with fix'
Confirmed kernel references
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:192
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:197
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:225
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:227
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:229
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:381
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c:1267
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.h:243
Detail
Exploit chain
EEPROM control (malicious/spoofed NIC or corrupted EEPROM) -> ath_hal_legacyEepromAttach at probe/module-load -> eepromExpandPower5112 wild heap write (semi-controlled 16-bit values, ~1.14MB offset, repeatable per mode/pier) -> heap corruption; panic/DoS realistic, uid0 chain not pursued (hardware-gated primitive, no leak-free grooming control demonstrated)
Evidence (decisive lines)
run.log lines 'damaged bytes past allocation: 18 (first at pDataPerChannel+1140106)' and the wild-site hexdump '04 00 2a 00 3f 00 49 00 4e 00 2c 00 30 00 34 00 38 00' (all EEPROM-chosen); trigger_fixed run in the same log shows 0 damaged bytes and exit 0
PoC changes
Original sketch had no working harness; built sha256-gated verbatim extraction of eepromAllocExpnPower5112/eepromExpandPower5112 + 5112 typedefs from the guest's own /usr/src, shimmed allocator onto a 4 MiB canaried arena, fixed assembly ordering (defines before typedefs, storage after structs), regenerated malformed fix.diff with diff -u (git-apply verified), made build.sh PACK absolute and mirror the a/ tree layout for patch -p1.
Verified recommended fix
In eepromExpandPower5112, reject xpdMask with no set bits (kk == 0) exactly like the existing kk > 1 rejection; long term also sanity-check ee_xgain[] nibbles at readHeaderInfo time.
Verdict
Reproduced via source-faithful harness on the audit guest: with a 5112-layout (EEP_MAP 1) EEPROM whose ee_xgain[mode] nibble is 0, eepromExpandPower5112() (verbatim kernel code, sha256-gated extraction from the guest's /usr/src) uses its 0xDEAD sentinel xgainList[0] as the pDataPerXPD[] index and writes 18 EEPROM-chosen bytes at pDataPerChannel+4+0xDEAD*20 (~1.09 MiB past a ~92-byte heap allocation), once per calibration pier at an 84-byte stride. In-kernel trigger is hardware-gated (requires an AR5212-family NIC with blanked/malicious EEPROM; the QEMU guest has no ath hardware), so on-guest impact is none β same classification as sibling DF-1447. fix.diff (missing kk==0 guard) validated with the same harness: zero OOB writes, clean AH_FALSE.
No comments yet.