# DF-1211 — OOB read+write in AHCI NCQ error recovery (device-controlled log-page tag)

## Claim
`ahci_port_read_ncq_error()` (`sys/dev/disk/ahci/ahci.c:3486-3498`):
`err_slot = log->err_regs.type & ATA_LOG_10H_TYPE_TAG_MASK` is a 5-bit
(0-31) tag read from the device's READ LOG EXT page 10h (device-supplied,
DMA'd into `ap_err_scratch`). `ccb2 = &ap->ap_ccbs[err_slot]` (`ahci.c:3490`)
indexes `ap_ccbs[]` (sized for `sc_ncmds`, 4-32) **with no bounds check**.
If the OOB `ccb2->ccb_xa.state == ATA_S_ONCHIP`, `ahci.c:3495` does
`memcpy(&ccb2->ccb_xa.rfis, &log->err_regs, sizeof(struct ata_fis_d2h))`
(20 bytes of device data into the OOB ccb) plus two 1-byte writes at
`ahci.c:3497-3498`. The caller at `ahci.c:2804-2808` then writes
`ap_ccbs[err_slot].ccb_xa.state = ATA_S_ERROR` using the same bad slot.
A malicious device returning tag >= sc_ncmds ⇒ OOB read + OOB write.

## Verdict
**NOT TESTABLE on this audit guest** (real bug, traced line-by-line; fix
authored and compile-validated into the GENERIC kernel). See `VERDICT.md`.

## Why not reproduced here
- No AHCI/SATA controller on the guest (`pciconf -l` shows none; virtio-blk
  only), so `ahci(4)` never attaches and `ahci_port_read_ncq_error()` is
  never called.
- The malicious value comes from the ATA device's NCQ error log page
  (device-DMA'd), not from any userspace syscall; a benign device/QEMU model
  always returns a valid tag, so there is no unprivileged trigger.

## Trigger (threat model)
A malicious or buggy SATA/NCQ device (or a malicious VM host's disk device
model) returning a READ LOG EXT page 10h whose tag field >= the host's
`sc_ncmds`. Same peripheral / malicious-device-model class as DF-1210.

## Fix
`fix.diff` adds the bounds check `err_slot < 0 || err_slot >= sc_ncmds`
after decoding the tag and before `ap_ccbs[err_slot]`, routing a bad tag to
the function's existing `err:` cleanup (which sets `err_slot = -1`, causing
the caller to reset the port).
