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

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)

No comments yet.

PoC verification

Evidence pack

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

VERDICT.md
↓ download raw

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

fixed
↓ fix.diffper-fix-DF-2525

Confirmed 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.