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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4207 Β· 8 files
FileTypeDescriptionSize
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

fixed
baseline reproduced→ patch + rebuild →patched clean

fix.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'
↓ fix.diffper-fix-DF-4207

Confirmed kernel references

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.