# DF-2428 — bt.c (buslogic) unbounded scatter/gather copy

## Verdict: NOT REPRODUCED (hardware-gated) — source bug CONFIRMED real; fix.diff compiles.

**Classification:** `not_reproduced` / HW-gated / impact=none. No BusLogic HBA on this
guest. The SG overflow is **real in source**; the defense-in-depth `fix.diff`
**compiles cleanly** (`nativekernel rc=0`, `-Werror`, `-DINVARIANTS`).

### Why not reproduced (the gate)

The bug is in `btexecuteccb()` of the **bt(4) BusLogic SCSI HBA driver**
(`sys/dev/disk/buslogic/bt.c`). The guest has **no BusLogic PCI HBA**
(`pciconf -l`: no `0x104b/*`) and the `bt` module is **not loaded** (`kldstat`: only
`kernel`, `ehci.ko`, `xhci.ko`). The `CAM_SCATTER_VALID` path is in a dead SIM. The
only `pass0` is on the PIIX3 ata-cam bus (different SIM), so no BusLogic-attached
pass device exists.

Gate proof (this guest):
```
$ kldstat              ->  kernel, ehci.ko, xhci.ko   (no bt/buslogic)
$ pciconf -l           ->  no BusLogic (0x104b/*) / no SCSI HBA at all
$ camcontrol devlist   ->  only QEMU DVD-ROM (pass0) on PIIX3 ata-cam, not bt
```

### The source bug (real, cited `path:line`)

`sys/dev/disk/buslogic/bt.c`:
- `#define BT_NSEG 32` (`sys/dev/disk/buslogic/btreg.h:40`) and each CCB has a
  fixed `bt_sg_t *sg_list` of `BT_NSEG` entries (allocated `BT_NSEG` per CCB at
  `bt.c:832-846`).
- In `btaction`, the `CAM_SCATTER_VALID` branch casts `csio->data_ptr` to a segment
  array and hands `csio->sglist_cnt` (a **user-controlled `u_int16_t`**) straight to
  `btexecuteccb(bccb, segs, csio->sglist_cnt, 0)` (`bt.c:1053-1056`) with **no bound
  check**.
- `btexecuteccb` copies that many segments into `bccb->sg_list` via
  `sg = bccb->sg_list; while (dm_segs < end_seg) { sg->len=...; sg->addr=...; sg++; }`
  (`bt.c:1260-1266`), where `end_seg = dm_segs + nseg` (`:1257`). Any
  `sglist_cnt > 32` writes attacker-controlled `{addr,len}` tuples past the end of
  the SG slot, corrupting adjacent CCBs / SG lists / neighboring kernel heap.
- The only thing that normally caps `nseg` at 32 is `buffer_dmat` DMA tag
  `nsegments=BT_NSEG` (`bt.c:618`), enforced **solely** inside `bus_dmamap_load()`;
  the `CAM_SCATTER_VALID` branch bypasses `bus_dmamap_load` entirely.

Attacker model (per finding): local user issuing `CAMIOCOMMAND XPT_SCSI_IO` with
`CAM_SCATTER_VALID` and `sglist_cnt > 32` through a `/dev/passN` on a bt bus.

### Exploit chain

Not developed — no BusLogic HBA, hence no bt-attached pass device. Valid hard
blocker: the SIM is not instantiated on this guest.

### Fix (defense-in-depth, validated to compile)

`fix.diff` rejects `csio->sglist_cnt > BT_NSEG` at the `CAM_SCATTER_VALID` call site
(`btfreeccb` + `CAM_PROVIDE_FAIL` + `xpt_done`). Validated in the combined
`nativekernel` build (`fix_build.log`).

### Reproduce

No runnable PoC on this guest (no bt HBA). Artifacts: `env.txt`, `fix.diff`,
`fix_build.log`.
