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

siba_pci_sprom dispatches rev-4/5/8 parsers without validating buffer size -> heap OOB read past 64-word buffer

Summary

siba_pci_sprom at siba_core.c:1372-1437: first allocs 64-word buf (SIBA_SPROMSIZE_R123), only reallocs to 220 words if CRC fails. Dispatches r45/r8 based on rev byte without checking buffer size. siba_sprom_r45 indexes word 151 (SIBA_SPROM4_PWR_INFO_CORE3), r8 indexes word 201. If 64-word path taken -> OOB read up to 276 bytes past 128-byte allocation. Crafted SPROM: R123 CRC-8 valid + rev byte=4/5/8. Fix: validate siba_spromsize>=SIBA_SPROMSIZE_R4 when rev>=4.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1287 Β· 8 files
FileTypeDescriptionSize
trigger_analysis.c trigger-source documentation marker 900 B view raw
fix.diff suggested-fix validate siba_spromsize >= SIBA_SPROMSIZE_R4 before dispatching to r45/r8 parsers 1.9 KB view raw
build.sh build-script syntax-checks the marker 432 B view raw
run.sh run-script documents INCONCLUSIVE status 647 B view raw
combined_build.log build-log combined X86_64_GENERIC rebuild log; rc=0 5.6 MB ↓ download
env.txt environment uname, pciconf -l, kldstat -v 1015 B view raw
README.md readme human-readable summary 3.3 KB ↓ raw
VERDICT.md verdict detailed source-level analysis 4.2 KB ↓ raw
README.md readme human-readable summary
↓ download raw

DF-1287 β€” siba_pci_sprom dispatches rev-4/5/8 parsers without buffer-size check

Finding

siba_pci_sprom (sys/dev/netif/bwn/siba/siba_core.c:1372) initially allocates a 64-word SPROM buffer (SIBA_SPROMSIZE_R123 = 64, sibareg.h:303) at line 1378, reads it via siba_sprom_read at line 1382 (which also sets siba->siba_spromsize = 64), and runs a CRC check at line 1383.

Only if the CRC fails does it free and realloc a 220-word (SIBA_SPROMSIZE_R4 = 220, sibareg.h:304) buffer at lines 1385-1390.

Then at line 1398 it extracts the SPROM revision byte from the last word of whatever buffer it ended up with, and dispatches to a per-revision parser (lines 1403-1428): - rev 1/2/3 β†’ siba_sprom_r123 (stays within 64 words) - rev 4/5 β†’ siba_sprom_r45 - rev 8 β†’ siba_sprom_r8

siba_sprom_r45 indexes SIBA_SPROM4_PWR_INFO_CORE0 = 0x1080 (sibareg.h:402) through SIBA_SPROM4_PWR_INFO_CORE3 = 0x110A (sibareg.h:405). With SIBA_OFFSET(o) = (o - SIBA_SPROM_BASE) / 2 and SIBA_SPROM_BASE = 0x1000 (sibareg.h:305), this is word index 64..133 plus the per-core pa offsets, well beyond the 64-word R123 buffer. Similarly siba_sprom_r8 indexes up to word ~158 (SIBA_SPROM8_CDDPO = 0x1192, SIBA_SPROM8_PWR_INFO_CORE3 = 0x1120, etc.).

The trigger is straightforward: a crafted SPROM image whose 64-word R123 CRC-8 is valid (so the realloc path is skipped), and whose last byte encodes rev 4, 5, or 8. The next siba_sprom_r45 / r8 call then reads up to ~276 bytes past the 128-byte allocation.

Fix

Validate siba->siba_spromsize >= SIBA_SPROMSIZE_R4 before dispatching to siba_sprom_r45 or siba_sprom_r8 in any of the three dispatch sites (chipid 0x4321 path, rev 4/5 case, rev 8 case). If the buffer is too small, log a warning and fall back to the R123 parser (which is the only one guaranteed to fit).

Verification on this guest

  • The siba_bwn / bwn drivers are statically compiled in (device siba_bwn and device bwn in sys/config/X86_64_GENERIC:267-268) and present in kldstat -v (siba_bwn/bwn).
  • The QEMU guest has no Broadcom BCM43xx PCI NIC (pciconf -l shows only i440FX/PIIX/ACPI/virtio-net/virtio-blk/std-VGA), so siba_pci_probe never matches and siba_pci_sprom is never called. Bug is not runtime-triggerable on this guest.
  • Source-level confirmation:
  • siba_core.c:1378 β€” initial alloc is SIBA_SPROMSIZE_R123 * 2 = 128 bytes.
  • siba_core.c:1382-1383 β€” siba_sprom_read then CRC; realloc only on CRC fail.
  • siba_core.c:1398 β€” sprom->rev = buf[siba_spromsize - 1] & 0xff.
  • siba_core.c:1408, 1418, 1421 β€” dispatch to r45 / r8 with no buffer size check.
  • siba_core.c:1632-1710 β€” siba_sprom_r45 accesses offsets SIBA_OFFSET(0x1080..0x110A + extra) = words 64..133+, far past 64.
  • siba_core.c:1727-1860 β€” siba_sprom_r8 accesses up to word ~158.
  • sibareg.h:303-305, 402-405 β€” confirming the constants.
  • Fix verified to compile (combined build with DF-1278/1279/1280/1285).

Realistic impact ceiling

Hardware-attacker (PCIe WiFi card or USB-attached Broadcom chip with crafted SPROM) heap OOB read past a 128-byte M_DEVBUF allocation at attach time. The read feeds struct siba_sprom fields β€” information leak of adjacent slab data is the realistic ceiling; no write primitive through this path.

VERDICT.md verdict detailed source-level analysis
↓ download raw

VERDICT β€” DF-1287

Status

INCONCLUSIVE (source-confirmed; not runtime-triggerable on this guest).

Mechanism (source-confirmed)

siba_pci_sprom (sys/dev/netif/bwn/siba/siba_core.c:1372):

  1. Line 1378 β€” allocates a 64-word buffer (SIBA_SPROMSIZE_R123 = 64, sibareg.h:303) β€” i.e. 128 bytes.
  2. Line 1382 β€” siba_sprom_read(siba, buf, SIBA_SPROMSIZE_R123) reads 64 words and sets siba->siba_spromsize = 64.
  3. Line 1383 β€” runs sprom_check_crc(buf, siba->siba_spromsize) on the 64-word image.
  4. Lines 1384-1394 β€” only if CRC fails, free + realloc a 220-word buffer (SIBA_SPROMSIZE_R4 = 220, sibareg.h:304).
  5. Line 1398 β€” sprom->rev = buf[siba_spromsize - 1] & 0xff.
  6. Lines 1403-1428 β€” dispatch on siba->siba_chipid then on sprom->rev: - rev 1/2/3 β†’ siba_sprom_r123 (stays within 64 words). - rev 4/5 β†’ siba_sprom_r45 - rev 8 β†’ siba_sprom_r8

siba_sprom_r45 (siba_core.c:1632) walks SIBA_SPROM4_PWR_INFO_CORE0..3 (sibareg.h:402-405: 0x1080..0x110A) plus per-core offsets, i.e. SIBA_OFFSET = (0x1080..0x110A - SIBA_SPROM_BASE) / 2 = 64..133, far past the 64-word buffer. siba_sprom_r8 (siba_core.c:1727) walks SIBA_SPROM8_* constants up to SIBA_SPROM8_CDDPO = 0x1192 (sibareg.h:523), i.e. SIBA_OFFSET = 0xc8 = 200, plus the SIBA_SHIFTOUT_4 macro adds another +2 β†’ word 202.

The trigger is a crafted SPROM image with a valid 64-word R123 CRC and a last byte claiming rev 4/5/8. siba_sprom_r45 / r8 then read up to ~276 bytes past the 128-byte allocation. The read values are written into struct siba_sprom fields.

Fix

Validate siba->siba_spromsize >= SIBA_SPROMSIZE_R4 before dispatching to siba_sprom_r45 / siba_sprom_r8 in any of the three dispatch sites (chipid 0x4321 path, rev 4/5 case, rev 8 case). If too small, log a warning and fall back to siba_sprom_r123 (the only parser guaranteed to fit). See fix.diff.

Verification on this guest

  • siba_bwn and bwn are statically compiled in (device siba_bwn, device bwn at sys/config/X86_64_GENERIC:267-268).
  • No Broadcom BCM43xx PCI NIC in pciconf -l (only i440FX/PIIX/ACPI/ virtio-net/virtio-blk/std-VGA), so siba_pci_probe never matches and siba_pci_sprom is never called. Not runtime-triggerable.
  • Source-level proof:
  • siba_core.c:1378 β€” initial alloc SIBA_SPROMSIZE_R123 * 2 = 128 bytes.
  • siba_core.c:1382-1383 β€” read + CRC.
  • siba_core.c:1384-1394 β€” realloc only on CRC fail.
  • siba_core.c:1398 β€” sprom->rev = buf[siba_spromsize - 1] & 0xff.
  • siba_core.c:1408, 1418, 1421 β€” dispatch to r45 / r8 with no size check.
  • siba_core.c:1632-1710 β€” siba_sprom_r45 reads words 64..133+.
  • siba_core.c:1727-1860 β€” siba_sprom_r8 reads up to word ~202.
  • sibareg.h:303-305, 402-405, 523, 532, 557 β€” confirming the constants.
  • Fix validation: combined X86_64_GENERIC rebuild with this fix applied exited rc=0. Full log: combined_build.log.

Exploit chain

None. The primitive is a kernel-heap OOB read past a 128-byte M_DEVBUF allocation. The read values feed struct siba_sprom fields (wireless calibration data). The realistic ceiling is information leak of adjacent slab data; there is no write primitive through this path.

Realistic impact ceiling

Hardware-attacker (PCIe WiFi card or USB-attached Broadcom chip with crafted SPROM) heap OOB read at attach time. CVSS: AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H β€” AV:L because physical access is the realistic vector (an external WiFi NIC); the read is large enough (up to ~276 bytes) to leak substantial kernel heap.

PoC changes

Folder was empty; added trigger_analysis.c, build.sh, run.sh, README.md, this VERDICT.md, fix.diff, manifest.json, combined_build.log.

Matches the finding proposal: validate siba_spromsize >= SIBA_SPROMSIZE_R4 before dispatching to r45/r8. See fix.diff. The implementation falls back to siba_sprom_r123 rather than skipping the parser entirely, so that already-present R123 fields (MAC, board info) are still populated.

Fix status

not_testable β€” bug requires absent hardware. fix.diff applies cleanly and compiles into X86_64_GENERIC (combined build rc=0).

Fix verification

not_testable

compile validated

nativekernel rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. siba_pci_sprom r45/r8 parsers on undersized 64-word buffer -> ~276B heap OOB read. siba_bwn in GENERIC, no Broadcom WiFi.