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

SPROM rev4/5/8 TXPID parser reads kernel heap at negative array indices (unported offset constants)

Summary

siba_sprom_r458 at siba_core.c:1591-1628: SIBA_SHIFTOUT(txpid2g[0],SIBA_SPROM4_TXPID2G01,...) uses SIBA_SPROM4_TXPID2G01=0x0062. SIBA_OFFSET subtracts SIBA_SPROM_BASE=0x1000: SIBA_OFFSET(0x0062)=(0x0062-0x1000)/2=-1999. 16 reads at in[-1999..-1992] -> 32 bytes of kernel heap read 3984-3998 bytes BEFORE the SPROM buffer allocation. Constants are Linux-style relative (0x0062-0x0070), not converted to absolute (0x1062-0x1070) like all sibling constants. SPROM rev 4/5/8 dominant format on BCM4321/4322/4325/4328. OOB bytes surface via SIBA_SPROMVAR_TXPID_* -> KASLR bypass. Fix: change constants to 0x1062-0x1070.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1286 Β· 12 files
FileTypeDescriptionSize
harness.c trigger-source object-level proof: replays SIBA_OFFSET/SIBA_SHIFTOUT with as-shipped vs fixed TXPID constants 4.9 KB view raw
fix.diff suggested-fix corrects 8 TXPID offset constants 0x006x/0x0070 -> 0x106x/0x1070 (absolute) 1.6 KB view raw
build.sh repro-script cc -O2 -o harness harness.c 101 B view raw
run.sh repro-script ./harness 60 B view raw
build.log build-log harness build, full output 65 B view raw
run.log run-log harness decisive run: negative indices -1999..-1992, fixed index 49 1.8 KB view raw
leak_sample.txt leak-sample RESULT line: 32 bytes heap leak per SPROM rev4/5/8 parse 231 B view raw
env.txt environment uname + cc version 188 B view raw
README.md readme summary + reproduce 2.8 KB ↓ raw
VERDICT.md verdict full mechanism + reachability + fix + compile validation 4.3 KB ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme summary + reproduce
↓ download raw

DF-1286 β€” SPROM rev4/5/8 TXPID parser reads kernel heap at negative indices (unported offset constants)

File: sys/dev/netif/bwn/siba/sibareg.h:363-386 (buggy constants); sink: sys/dev/netif/bwn/siba/siba_core.c:1513 / :1591-1628 Class: CWE-125 Out-of-bounds Read (kernel heap info leak) Severity: High

The bug (source-confirmed)

siba_sprom_r458() (siba_core.c:1591) parses the Broadcom SPROM TX-power-id fields for SPROM revisions 4/5/8 (the dominant format on BCM4321/4322/4325/4328). Each field is read via the macro (siba_core.c:1513):

#define SIBA_OFFSET(offset)  (((offset) - SIBA_SPROM_BASE) / sizeof(uint16_t))  /* :1509 */
#define SIBA_SHIFTOUT(_var, _offset, _mask) \
        out->_var = SIBA_SHIFTOUT_SUB(in[SIBA_OFFSET(_offset)], (_mask))        /* :1513 */

SIBA_SPROM_BASE = 0x1000 (sibareg.h:305). For SIBA_OFFSET to yield a valid non-negative word index, the constant must be an absolute byte address in the 0x10xx range. Every sibling SIBA_SPROM4_* offset constant is absolute β€” e.g. MAC_80211BG=0x104c, BFHIGH=0x1046, AGAIN23=0x1060, MAXP_BG=0x1080.

But the TXPID block (sibareg.h:363-386) was left as Linux-style relative word offsets:

constant value SIBA_OFFSET
SIBA_SPROM4_TXPID2G01 0x0062 -1999
SIBA_SPROM4_TXPID2G23 0x0064 -1998
SIBA_SPROM4_TXPID5G01 0x0066 -1997
... ... ...
SIBA_SPROM4_TXPID5GH23 0x0070 -1992

siba_sprom_r458 therefore performs in[-1999 .. -1992] β€” 16 reads (8 offsets, each used for two TXPID values) of kernel heap 3984–3998 bytes before the SPROM buffer allocation. The leaked words surface to userland as the SIBA_SPROMVAR_TXPID_* sysctl spromvars (a kernel-heap / KASLR-bypass info leak).

Reachability / threat model

The bwn/siba driver attaches to Broadcom BCM43xx (PCI/CardBus) WiFi. No such device is present in the audit QEMU guest, so siba_sprom_r458 is not runtime-reachable here. On hardware, the parse runs at attach time (boot or device insertion), and the result is world-readable via sysctl. This is a straight porting bug β€” the fix is purely a constant correction. See VERDICT.md.

Reproduce (harness)

./build.sh && ./run.sh

Decisive output:

constant 0x0062 -> SIBA_OFFSET = -1999 => NEGATIVE: in[-1999] reads -3998 bytes BEFORE the SPROM buffer (heap leak)
...
FIXED constants 0x1062..0x1070: SIBA_OFFSET(0x1062) = 49 -> in[49] reads the REAL SPROM word

Fix

fix.diff corrects the 8 TXPID offset constants to absolute values (0x0062β†’0x1062 … 0x0070β†’0x1070), matching every sibling SPROM4 constant and the SPROM1 PA0B2=0x1062 already in this file. Validated: applies cleanly; the siba_bwn module compiles with -Werror in-tree.

VERDICT.md verdict full mechanism + reachability + fix + compile validation
↓ download raw

DF-1286 β€” VERDICT

Verdict: REPRODUCED (primitive confirmed at object/harness level; runtime path is hardware-bound and not present on the audit guest).

Mechanism (source trace)

The siba/bwn SPROM parser reads Broadcom SPROM fields via two macros (sys/dev/netif/bwn/siba/siba_core.c):

#define SIBA_OFFSET(offset)  (((offset) - SIBA_SPROM_BASE) / sizeof(uint16_t))   /* :1509 */
#define SIBA_SHIFTOUT(_var, _offset, _mask) \
        out->_var = SIBA_SHIFTOUT_SUB(in[SIBA_OFFSET(_offset)], (_mask))         /* :1513 */

in is a const uint16_t * pointing at the kmalloc'd SPROM image. SIBA_SPROM_BASE is 0x1000 (sibareg.h:305), so a valid offset constant must be an absolute byte address in the 0x10xx range for SIBA_OFFSET to yield a non-negative word index.

siba_sprom_r458 (siba_core.c:1591-1628) performs 16 SIBA_SHIFTOUT calls for the TXPID fields, using the constants in sibareg.h:363-386. Those 8 offset constants are 0x0062, 0x0064, 0x0066, 0x0068, 0x006a, 0x006c, 0x006e, 0x0070 β€” Linux-style relative word offsets that were never converted to absolute when the code was ported. Every other SIBA_SPROM4_* offset in the same file is absolute (MAC_80211BG=0x104c, BFHIGH=0x1046, AGAIN23=0x1060, MAXP_BG=0x1080, PWR_INFO_CORE0=0x1080 …), and SIBA_SPROM1_PA0B2=0x1062 already exists at sibareg.h:323, confirming 0x1062 is a valid absolute offset.

The arithmetic: SIBA_OFFSET(0x0062) = (0x0062 - 0x1000)/2 = -1999. The 8 constants map to indices -1999 .. -1992, i.e. in[-1999] reads 3998 bytes before the SPROM buffer β€” into unrelated kernel heap. 16 reads Γ— 2 bytes = 32 bytes of kernel heap leaked per SPROM rev4/5/8 parse. The values surface to userland through the SIBA_SPROMVAR_TXPID_* sysctl spromvars (read by bwn / siba), making this a kernel-heap / KASLR-bypass information leak.

Primitive characterization

  • Read size: 16 Γ— uint16_t = 32 bytes of kernel heap.
  • Location: 3984–3998 bytes before the SPROM kmalloc (slab-resident heap).
  • Sink to userland: the parsed TXPID values are exported as sysctl spromvars, so the leaked heap bytes are directly readable by an unprivileged user once the device has attached.

This is a read-only primitive (no corruption), so per Phase 6 there is no escalation chain to develop β€” the impact ceiling is the info leak itself (kernel-heap disclosure / KASLR defeat).

Harness proof

harness.c reproduces the exact SIBA_OFFSET/SIBA_SHIFTOUT macros with the as-shipped and fixed constant values. Output (run.log):

constant 0x0062 -> SIBA_OFFSET = -1999  => NEGATIVE: in[-1999] reads -3998 bytes BEFORE the SPROM buffer (heap leak)
... (all 8 constants negative: -1999..-1992) ...
Simulated leak: buggy txpid2g[0] = 0xbe65 (heap residue before SPROM buf), NOT the real SPROM TXPID value.
FIXED constants 0x1062..0x1070: SIBA_OFFSET(0x1062) = 49 -> in[49] reads the REAL SPROM word
RESULT: BUG CONFIRMED -- 3998 bytes of kernel heap read before the SPROM buffer ... (16 reads = 32 bytes)

Why not a live in-kernel reproduction (valid hard blocker)

The bwn/siba driver attaches to Broadcom BCM43xx WiFi PCI/CardBus devices; the audit QEMU guest has no such device (only virtio + QEMU std-vga), so siba_sprom_r458 never runs here. Live trigger conditions: any system with a BCM4321/4322/4325/4328 (SPROM rev 4/5/8) WiFi adapter at attach/boot time. The bug is a pure constant error β€” the harness uses the kernel's exact macros and constant values, so the proof is equivalent to the in-kernel behavior. Honest reported impact: kernel-heap info leak (32 bytes per parse), surfacing via sysctl.

Fix

fix.diff corrects the 8 TXPID offset constants to absolute values (0x0062β†’0x1062 … 0x0070β†’0x1070). This matches the convention of every sibling SPROM4 constant and the pre-existing SIBA_SPROM1_PA0B2=0x1062 at sibareg.h:323. Validated: patch -p1 succeeds; the siba_bwn module builds with -Werror (siba_bwn.ko produced). Supersedes any pre-verification proposal.

Fix-validation status

not_testable for a live before/after (PoC path cannot run on the guest β€” no Broadcom WiFi). Evidence the fix is correct: (1) harness before/after shows the fixed constants yield valid index 49 instead of -1999; (2) the siba_bwn module with the fix compiles cleanly under -Werror in-tree.

Fix verification

not_testable

compile+harness validated

module build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED (harness). siba SPROM TXPID constants unported Linux-relative -> SIBA_OFFSET -1999 -> 32B heap leak. No Broadcom WiFi.