# DF-2425 — PoC evidence pack

**Finding**: CDB heap overflow via unchecked `cdb_len` into 12-byte `CmdBlock`
**File**: `sys/dev/disk/amd/amd.c:399-400` (sink), `sys/dev/disk/amd/amd.h:159` (`CmdBlock[12]`)
**Verdict**: **reproduced** (kernel memory corruption, production-code rig) · fix **validated**

## What was verified

1. **Static chain (host tree)** — no validation of `cdb_len` anywhere between the
   CAMIOCOMMAND ioctl and the driver sink:
   - `sys/bus/cam/scsi/scsi_pass.c:462` `CAMIOCOMMAND` → `passsendccb`
   - `sys/bus/cam/cam_xpt.c:3888` `xpt_merge_ccb()` — `bcopy`s the user's entire
     CCB payload (incl. `cdb_len`, `msg_ptr`) into the kernel ccb, verbatim
   - `sys/dev/disk/amd/amd.c:399-400` — `bcopy(cdb_bytes, CmdBlock[12], cdb_len)`
   - overflow bytes `CmdBlock[16..24)` land exactly on `struct amd_srb.pccb`;
     those source bytes are `ccb_scsiio.msg_ptr` (fully user-controlled)
   - `amd.c:287-288` dereferences the forged pointer immediately
2. **Hardware reality** — QEMU 7.2's `-device am53c974` (PCI 0x1022:0x2020) is
   matched by `amd_probe` (amd.c:2455): `amd0` attaches to real emulated silicon
   (`attach-am53c974-boot.log:103`). The XPT bus scan then wedges forever in the
   emulation (the driver has no timeout handler, amd.c:356-360 `#if 0`), so the
   end-to-end userland path could not complete on emulated hardware; the
   production-code KLD rig below was used instead (as sanctioned for
   hardware-absent drivers).
3. **Trust boundary (live on guest)** — `/dev/pass0` is `crw------- root:operator`;
   non-root open fails with EACCES. `device amd` is compiled into GENERIC
   (`sys/config/X86_64_GENERIC:88`) but dormant without the PCI card.
4. **Baseline reproduction (rig driving the real `amd_action`, unmodified
   `/usr/src` source)** — `panic.txt` + `panic.txt`:
   - controlled WRITE through the forged `pccb` (amd.c:355
     `ccb->ccb_h.status |= CAM_SIM_QUEUED` observed at the victim address),
     full deterministic SRB smash (`dmamap=0x00c0ffee005a1337`,
     `pSGlist=0x1234abcd`), guest survives;
   - panic proof: forged `pccb=0x414141414141` → `Fatal trap 12`, faulting
     address `0x4141414141c9` (attacker bytes + 0x88 = offsetof(ccb_hdr,
     ccb_amd_ptr)), stopped at `amdexecutesrb+0x12: movq 0x88(%r13),%r12`
     — exactly amd.c:288.
5. **Fix validation** — `fix.diff` (reject `cdb_len > sizeof(CmdBlock)` with
   `CAM_REQ_INVALID`) applied to guest `/usr/src`; rig module rebuilt against
   the patched source AND full `nativekernel` rebuild + install + reboot
   (kernel `#1 Mon Oct 12 08:57:10 UTC 2026`, sha256
   `1aecdc66d61423b7fd570f698e4df6a4d6d335c7779b95b30c609248910ee63b`):
   identical inputs → `RIGDONE: shim saw func=2305 status=0x6`
   (XPT_SCSI_IO / CAM_REQ_INVALID), SRB untouched, **no panic**, and a
   valid 6-byte CDB still queues normally (no functional regression).

## Layout

| file | what |
|---|---|
| `amdrig.c` | the rig: verbatim `#include` of production `amd.c`, driven like `amd_attach` does |
| `Makefile` | in-guest module Makefile (`make -C /usr/src/sys/modules/amdrig`) |
| `build.sh` / `run.sh` | exact host-side build/run commands |
| `build.log` | final successful baseline module build (full compiler output) |
| `run.log` | host-side run transcripts |
| `panic.txt` | baseline run, verbatim (write-demo + sanity + panic; the full baseline serial was lost when QEMU truncated boot.log on the subsequent reset — every RIG* line and the complete trap dump are preserved here) |
| `attach-am53c974-boot.log` | proof the real driver attaches to QEMU's emulated AMD 53C974 |
| `fix.diff` | git-apply-able clamp fix |
| `fix-apply.log` / `fix-module-build.log` / `fix-kernel-build.log` | patch + module + kernel rebuild logs |
| `fix-run-serial.log` / `fix-run2-serial-full.log` | patched-kernel runs (reject, no panic) |
| `fix-run.log` | host-side fixed-run transcript |
| `env.txt` / `kernel-patched.sha256` | guest environment, patched kernel hash |
| `VERDICT.md` | full narrative |
| `manifest.json` / `verdict.json` | machine-readable results |

## Reproduce

```sh
# guest is up (vm.sh up), /usr/src present:
./build.sh                      # module build (baseline: unpatched /usr/src)
kldload /usr/src/sys/modules/amdrig/amdrig.ko     # write-demo (survives)
sysctl dev.amdrig_fire=1                          # panic proof (panics)
# after vm.sh reset with-src:
./fix-apply-build.sh            # patch + module + nativekernel rebuild
# reboot, then: kldload ...; sysctl dev.amdrig_fire=1  -> clean reject, no panic
```

Expected on the **unpatched** kernel: `RIGW1 ... WRITE-THROUGH-FORGED-PTR-CONFIRMED`
and (mode 1) `Fatal trap 12 ... Stopped at amdexecutesrb+0x12`.
Expected on the **patched** kernel: `RIGDONE: shim saw func=2305 status=0x6`,
no write, no panic, mode 2 still queues normally.
