# DF-1891 — Verification Verdict

## Verdict: REPRODUCED (source-confirmed + index-harness)

The unbounded `ctlr->channels` from CAP/PI registers is confirmed at
`sys/dev/disk/nata/chipsets/ata-ahci.c:101-103`. The harness reproduces
the 192-byte OOB write into `ctlr->interrupt[8]` for a 32-port AHCI.

## Mechanism

```c
// ata-ahci.c:101-103
ctlr->channels =
    MAX(flsl(ATA_INL(ctlr->r_res2, ATA_AHCI_PI)),
        (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
```

`ctlr->channels` is taken directly from HW registers with no upper
bound. PI is a 32-bit port bitmap (`flsl` returns 0..32); CAP.NP is 5
bits (0..31 → +1 = 1..32). The downstream sink `ctlr->interrupt[]` is
sized 8 (ata-pci.h:67, "XXX SOS max ch# for now"). When `channels > 8`
(e.g. PI=0xFFFFFFFF → `flsl`=32, or CAP.NP=0x1f → 32),
`ata_pci_setup_intr` writes `controller->interrupt[unit]`
(ata-pci.c:383-384) for `unit = 0..channels-1`, writing
`(channels-8)*sizeof(void*)` bytes off the end. With channels=32:
`(32-8)*8 = 192` bytes OOB. `ata_generic_intr` (ata-pci.c:584-586) later
reads these corrupted slots and CALLS through them as function pointers
on every IRQ → kernel arbitrary code execution.

Trigger: a malicious/glitched PCIe AHCI device with CAP.NP=0x1f or
PI=0xFFFFFFFF; VFIO PCI passthrough with a crafted AHCI BAR; custom
QEMU `ahci` with `ports=32`; some legitimate server AHCI with >8 ports.

## Harness evidence

```
DF-1891: ata_ahci_chipinit (ata-ahci.c:101-103)
  AHCI CAP.NP = 0x1f -> 32 ports
  AHCI PI     = 0xffffffff -> flsl = 32
  ctlr->channels = 32 (NO upper bound vs interrupt[8])
  OOB interrupt[] writes = 24 entries x 8 bytes = 192 bytes past interrupt[8] into the controller struct
  Harness: simulated writes touched 24 trailer words (function pointers in real kernel)
  On real HW: ata_generic_intr (ata-pci.c:584-586) later CALLS through these corrupted pointers on every IRQ -> arbitrary kernel code exec.
```

## Why no live trigger on this guest

The audit guest's AHCI controller (the emulated QEMU `ahci` on the
primary disk) reports a small number of ports, so `channels <= 8` and
the OOB doesn't fire. Triggering requires a malicious AHCI BAR
(passthrough / custom QEMU / specific server HBA). Valid Phase-6 hard
blocker.

## Exploit chain

Not applicable (needs malicious AHCI HW). No `uid=0` claim. Live ceiling
on vulnerable HW: 192-byte heap OOB write + function-pointer call on
every IRQ → arbitrary kernel code execution / panic.

## PoC changes

- Added `harness.c`: flat model showing 192-byte OOB into interrupt[].
- Added `fix.diff`: cap `channels` at `nitems(ctlr->interrupt)`.

## Fix

`fix.diff` adds `ctlr->channels = MIN(ctlr->channels,
nitems(ctlr->interrupt))` right after the register-derived value is
computed, capping at the actual sink array size.

- BEFORE: harness shows 24 OOB interrupt[] writes (192 bytes).
- AFTER: channels is capped at 8, no OOB.
