# DF-3820 — aac(4) dereferences adapter-controlled FIB/queue indices with no bounds validation (malicious/errant controller → wild kernel pointers)

- **File:** `sys/dev/raid/aac/aac.c`
- **Lines:** 853, 1118, 2221-2223, 2238-2240, 3771-3772
- **Class:** CWE-129 (improper validation of array index) → OOB pointer
  formation → kernel memory read/write (device-trust)
- **Reach:** PCI device DMA / MMIO only (compromised or faulty controller
  firmware; no unprivileged-software path).

## What to look at

No runnable PoC exists without the hardware: every affected value is
produced by the adapter (MMIO read or DMA into the common block).  The
defect is proven by inspection at each site:

1. `aac_new_intr()` aac.c:853 — `cm = sc->aac_commands + (index >> 2);`
   `index` is read straight from `AAC_GET_OUTB_QUEUE()` (MMIO).  No check
   against `sc->total_fibs` / `aac_max_fibs`.  The subsequent
   `aac_remove_busy(cm)`, `aac_unmap_command(cm)`, `cm->cm_complete(cm)`
   operate on an arbitrary out-of-array `struct aac_command *`.
2. `aac_complete()` aac.c:1118 — `cm = sc->aac_commands +
   fib->Header.SenderData;` — `SenderData` lives in the DMA'd FIB the
   adapter filled.  The `if (cm == NULL)` guard at :1119 is dead (array
   offset can never be NULL); there is no range check.
3. `aac_dequeue_fib()` aac.c:2221-2223 — AIF path:
   `fib_index = aq_fib_addr / sizeof(struct aac_fib);
   *fib_addr = &sc->aac_common->ac_fibs[fib_index];` — `aq_fib_addr` is a
   32-bit queue entry the adapter writes; `ac_fibs` has exactly
   `AAC_ADAPTER_FIBS` (8) slots (aacvar.h:71,217).  A 32-bit index up to
   0x1FFFFFF yields a pointer ~4 GB past the common block → the AIF is
   then copied/processed from arbitrary kernel memory.
4. `aac_dequeue_fib()` aac.c:2238-2240 — response path:
   `cm = sc->aac_commands + (fib_index >> 2); *fib_addr = cm->cm_fib;` —
   same: `fib_index` is the adapter-written `aq_fib_addr`, unbounded;
   `cm->cm_fib` dereferences the OOB command slot.
5. `aac_get_bus_info()` aac.c:3771-3772 — `for (i = 0; i <
   businfo.BusCount; i++) { ... businfo.BusValid[i] ...
   businfo.InitiatorBusId[i] }` — `BusCount` is an adapter-supplied u32;
   both arrays have `AAC_SCSI_MAX_PORTS` (10) entries
   (aacreg.h:struct aac_getbusinf).  OOB *stack* read of the local
   `businfo` copy, up to a wild read when `BusCount` is huge.

## Impact ceiling

A compromised/faulty AAC controller (or anything able to DMA on its
behalf) turns each site into a controlled kernel write: e.g. pick
`SenderData` so that the bogus `cm` aliases chosen memory, then the
completion path performs `callout_stop`, `TAILQ_REMOVE` (unlink writes)
and an indirect call through `cm->cm_complete`.  Severity capped at Low
because the precondition is hardware/firmware compromise.

## Verdict

`inconclusive` — no AAC HBA exists on the audit guest
(see ../DF-3819/env.txt); the code paths are reachable only from adapter
DMA/MMIO.  Source-level: certain.
