crom_parse_text() CROM_END check treats crc_len as bytes instead of quadlets, allowing OOB read past csrrom
Summary
Bounds check at fwcrom.c:207 is (vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc), but crc_len counts 32-bit quadlets not bytes (compare its use at :215,:218 where text[i] indexed as u_int32_t and qlen=crc_len-2 looped as quadlets). Check too permissive by ~4x. With info_len=4 stack[0].dir=&csrrom[5], CROM_END=&csrrom[5]+1003. textleaf at offset 983 with crc_len=20: check 983+20>1003 false (passes), but textleaf->text[7] at byte offset 983+12+28=1023..1026 crosses csrrom/rommax boundary. Bytes copied to sdev->vendor[0..31] then bcopy to SCSI INQUIRY response (sbp.c:1527) exposing leaked rommax/rcnt kernel values to any userland CAM inquiry. Fix: multiply crc_len by sizeof(u_int32_t) and account for full leaf size.
Discussion (0)
PoC verification
Evidence pack
findings/poc/1086 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| poc_firewire.c | trigger-source | shared fwcrom OOB harness (real parser, TEST mode) | 5.9 KB | view raw |
| build.sh | build-script | compile real fwcrom.c (TEST) + harness, link | 581 B | view raw |
| run.sh | run-script | ./poc_firewire | 188 B | view raw |
| run.log | run-log | baseline: 60+ bytes OOB poison copied by crom_parse_text | 1.3 KB | view raw |
| fix.diff | suggested-fix | scale crc_len bound by sizeof(u_int32_t) | 646 B | view raw |
| env.txt | environment | uname, cc version | 232 B | view raw |
| VERDICT.md | verdict | full narrative | 1.9 KB | β raw |
DF-1086 β crom_parse_text CROM_END check treats crc_len as bytes (OOB read)
Verdict: REPRODUCED (out-of-bounds read past the 1024-byte csrrom)
crom_parse_text() (sys/bus/firewire/fwcrom.c:187-225) bounds-checks the
text leaf with:
fwcrom.c:207 if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) ...
but crc_len counts 32-bit quadlets, not bytes β the loop immediately
below indexes textleaf->text[i] as u_int32_t with qlen = crc_len - 2
(:215-219). The check is therefore ~4Γ too lax: a text leaf whose
crc_len fits the byte bound still reads text[i] quadlets far past the
csrrom buffer.
Concrete: root dir at quad 5 (info_len=4), text leaf at quad 250,
crc_len = 20.
- byte-check (:207): textleaf(1000) + 20 = 1020 <= 1023 β PASSES
- quad loop (:218): qlen = 18, reads text[0..17] = quads 253..270 β
quads 256..270 are out-of-bounds (15 quads = 60 bytes OOB).
Reproduction (no FireWire hardware needed)
Same harness as DF-1084 (links the real -DTEST parser):
crom_parse_text output bytes (hex): 42424242 ... (60+ bytes of 0x42 OOB poison)
[+] DF-1086 CONFIRMED: crom_parse_text copied 60+ bytes of OOB memory via the
byte-vs-quad crc_len check bug at fwcrom.c:207.
In the kernel these OOB bytes are adjacent fw_device/ConfigROM fields
exposed to userland via sdev->vendor β SCSI INQUIRY (sbp.c:1527), i.e. an
info leak of kernel heap values to any CAM inquiry.
Reachability
Same as DF-1084: FireWire in GENERIC (DF-1083), parser exercised at device attach; no FW controller on the audit guest, so demonstrated against the real parser code. Impact ceiling: kernel info-leak / panic.
Fix (validated at harness level)
fix.diff scales the bound by sizeof(u_int32_t):
if ((vm_offset_t)textleaf + (size_t)textleaf->crc_len * sizeof(u_int32_t) > CROM_END(cc)).
Re-linked harness returns the "(null)" fallback with 0 OOB bytes copied.
Fix verification
fixedvalidated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
REPRODUCED (harness, real parser). crom_parse_text crc_len bytes-vs-quads -> 60B OOB read.
No comments yet.