trm_check_eeprom default-load writes 8-byte u_long into 4-byte field schema 122-byte OOB write of static trm_eepromBuf[] on x86_64 at attach
Summary
trm_check_eeprom EEPROM-default init code written for ILP32 where u_long is 4 bytes. On x86_64 u_long is 8 bytes so each *dpEeprom write 8 bytes instead of 4. First loop (16 iters) writes 128 bytes into NvramTarget[64] overflow 64 bytes. Two single writes add 16 bytes. 12-iteration zeroing loop adds 96 bytes. Total 240 bytes from offset 10 of NVRAM_STRUC(128 bytes) 122-byte overflow into adjacent trm_eepromBuf elements and for last adapter past array into BSS. Data written is constant (0x77 0x07 0x15 zeros) not attacker-controlled. Triggered whenever NVRAM checksum wrong. [VERIFIED pass2: reproduced - bad-checksum default load ILP32 u_long stores smash exactly 122 bytes past the 128-byte NVRAMTYPE hex-captured; u32 store fix A/B zero spill]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2525 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.0 KB | β raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| build.sh | β | 99 B | view raw | |
| run.log | β | 428 B | view raw | |
| env.txt | β | 963 B | view raw | |
| fix.diff | β | 1.7 KB | view raw | |
| manifest.json | β | 751 B | view raw | |
| verdict.json | β | 2.4 KB | view raw |
DF-2525 -- trm_check_eeprom ILP32 u_long stores overflow the 128-byte NVRAM struct on x86_64
Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_trm (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.
Build
sh build.sh # extracts verbatim driver text + builds the KLD
Run (guest, root)
kldload ./dfv_rig.ko
kldload dfv_trm.ko; sysctl kern.dfv_trm_run=0; sysctl -n kern.dfv_trm_status; sysctl kern.dfv_trm_run=1; sysctl -n kern.dfv_trm_status
Expected
run.log: smashed=122 first=128 last=249 with hex dump of the spill; control clean; fixed clean.
Fix validation
fix.diff switches the walk to u_int32_t and shrinks the zero loop to 11 words; A/B zero spills.
Verdict: reproduced / impact=limited_write (see verdict.json, VERDICT.md)
DF-2525 verdict -- trm_check_eeprom ILP32 u_long stores overflow the 128-byte NVRAM struct on x86_64
status: reproduced reproduced: 1 impact: limited_write confidence: certain attempts: 1 runtime_sec: 500
The verbatim trm_check_eeprom default-load writes u_long (8 bytes on x86_64) per store into a schema of 4-byte NVRAMTARGETTYPE words: 16 + 2 + 12 stores starting at &NvramTarget (offset 10) span offsets 10..257 of a 128-byte NVRAMTYPE. With a failed checksum the verbatim function smashed EXACTLY 122 guard bytes past the struct end (first=128, last=249; guard values 128..383 monitored) - the exact figure in the finding - writing constants (0x77/0x07/0x0f/0x15/0) into what is really trm_eepromBuf[unit+1..] (the following adapters EEPROM image) or, for the last adapter, past the array in BSS. Control (checksum good) touches nothing. Fixed source (u_int32_t stores + 11-word zero loop - the original also overran by 2 bytes even on ILP32) A/B: zero guard bytes touched.
Evidence (decisive lines)
DF2525[BAD-CHECKSUM]: sizeof(NVRAMTYPE)=128 NvramTarget offset=10 sizeof(u_long)=8 0078: 00 00 77 00 00 00 a9 77 00 00 77 00 ... <- 8-byte straddling stores DF2525: guard bytes 128..383 smashed=122 first=128 last=249 -> 122 bytes past the 128-byte struct end touched DF2525: RESULT=OOB WRITE (ILP32 u_long stores spill past NVRAMTYPE) --- control (checksum good) --- smashed=0 clean --- fixed source A/B --- smashed=0 clean
Exploit chain / privesc assessment
attach-time constant-data corruption of adjacent NVRAM images (not attacker-valued); triggered by a bad EEPROM checksum; Low as filed.
Fix + A/B
fix.diff switches the walk to u_int32_t and shrinks the zero loop to 11 words; A/B zero spills.
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
fixedConfirmed kernel references
Detail
Exploit chain
attach-time constant-data corruption of adjacent NVRAM images (not attacker-valued); triggered by a bad EEPROM checksum; Low as filed.
Evidence (decisive lines)
run.log: smashed=122 first=128 last=249 with hex dump of the spill; control clean; fixed clean.
PoC changes
NVRAM accessors interposed to force checksum fail/succeed; guard region after the struct in one allocation.
Verified recommended fix
use u_int32_t stores and 11 (not 12) zero words in the EEPROM default load
Verdict
The verbatim trm_check_eeprom default-load writes u_long (8 bytes on x86_64) per store into a schema of 4-byte NVRAMTARGETTYPE words: 16 + 2 + 12 stores starting at &NvramTarget (offset 10) span offsets 10..257 of a 128-byte NVRAMTYPE. With a failed checksum the verbatim function smashed EXACTLY 122 guard bytes past the struct end (first=128, last=249; guard values 128..383 monitored) - the exact figure in the finding - writing constants (0x77/0x07/0x0f/0x15/0) into what is really trm_eepromBuf[unit+1..] (the following adapters EEPROM image) or, for the last adapter, past the array in BSS. Control (checksum good) touches nothing. Fixed source (u_int32_t stores + 11-word zero loop - the original also overran by 2 bytes even on ILP32) A/B: zero guard bytes touched.
No comments yet.