# DF-2424 — amd.c scatter/gather list heap overflow via unchecked sglist_cnt

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

**Classification:** `not_reproduced` / HW-gated / impact=none. No AMD 53c974 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 `amdexecutesrb()` of the **amd(4) SCSI HBA driver**
(`sys/dev/disk/amd/amd.c`, AMD 53c974). The guest has **no AMD SCSI HBA**
(`pciconf -l`: no `0x1022/0x2020`) and the `amd` module is **not loaded**. The
`CAM_SCATTER_VALID|CAM_SG_LIST_PHYS` path is in a dead SIM. The trigger would also
need a `/dev/passN` on an amd bus with a crafted CCB; the only `pass0` here is on the
PIIX3 ata-cam bus, served by a different SIM.

Gate proof (this guest):
```
$ kldstat              ->  kernel, ehci.ko, xhci.ko   (no amd)
$ pciconf -l           ->  no AMD 53c974 / no SCSI HBA at all
$ camcontrol devlist   ->  only QEMU DVD-ROM (pass0) on PIIX3 ata-cam, not amd
```

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

`sys/dev/disk/amd/amd.c`:
- `#define AMD_NSEG (btoc(MAXPHYS) + 1)` (`sys/dev/disk/amd/amd.h:99`; MAXPHYS=128KiB
  → AMD_NSEG = 33) and `struct amd_sg SGsegment[AMD_NSEG];` (`amd.h:170`) — a
  **fixed 33-entry** SG array inside each SRB.
- In `amd_action`, the `CAM_SCATTER_VALID|CAM_SG_LIST_PHYS` branch hands
  `pcsio->sglist_cnt` (a **user-controlled `u_int16_t`, up to 65535**) straight to
  `amdexecutesrb(pSRB, segs, pcsio->sglist_cnt, 0)` (`amd.c:455`).
- `amdexecutesrb` copies that many 8-byte `amd_sg` entries into the fixed
  `srb->SGsegment[AMD_NSEG]` array via `sg = srb->pSGlist; sg++;`
  (`amd.c:311-318`), with **no bounds check**. Any `sglist_cnt > 33` overflows the
  SRB object and corrupts the contiguous `SRB_array[256]`.
- `srb->SGcount = nseg;` (`:328`) truncates `nseg` to `u_int8_t`, so e.g.
  `sglist_cnt=256` becomes `SGcount=0` *after* the 256-entry overflow already
  happened. The `bus_dmamap_load` path is safe (`buffer_dmat` nsegments=AMD_NSEG,
  `amd.c:2297`), but the `CAM_SG_LIST_PHYS` path bypasses `bus_dmamap_load`.

Attacker model (per finding): local user issuing `CAMIOCOMMAND XPT_SCSI_IO` with
`CAM_SCATTER_VALID|CAM_SG_LIST_PHYS` and `sglist_cnt > 33` through a `/dev/passN` on
an amd bus.

### Exploit chain

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

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

`fix.diff` rejects `pcsio->sglist_cnt > AMD_NSEG` at the `CAM_SG_LIST_PHYS` call site
(`CAM_PROVIDE_FAIL` + `xpt_done`). Validated in the combined `nativekernel` build
(`fix_build.log`).

### Reproduce

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