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)
PoC verification
Evidence pack
findings/poc/DF-1286 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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.
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_testablecompile+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.
No comments yet.