# 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`):

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