# DF-4809 — `ata_ahci_reset()` NULL `ch->dma` dereference when DMA workspace alloc failed

File: `sys/dev/disk/nata/chipsets/ata-ahci.c` (pass 2)
Severity: Low · CWE-476 (NULL pointer dereference) · confidence: likely
(class: robustness / boot-time panic; not the DF-1891/DF-2510 unbounded-channels family)

## Build / run

Not applicable — this is a static control-flow finding. There is no buildable,
runnable PoC: the trigger is `ata_dmaalloc()` failure (bus_dmamem_alloc /
bus_dma_tag_create failing for the 4 KB `sg` + 8 KB `work` DMA areas) during
ATA channel attach, i.e. DMA-coherent memory exhaustion at device attach time.
Verification on the QEMU guest was therefore **not attempted** (Phase V bar
not met: not Critical/High, not memcorrupt/privesc, no trivial local program).

## The path (all citations from this tree)

1. `ata_pcichannel_attach()` — `sys/dev/disk/nata/ata-pci.c:790-793`:
   `ctlr->dmainit(dev)` then **`if (ch->dma)`** `ch->dma->alloc(dev)`.
   For AHCI, `dmainit = ata_ahci_dmainit` (set at `ata-ahci.c:106`),
   `alloc = ata_dmaalloc` (set at `ata-dma.c:69`).
2. `ata_dmaalloc()` — `sys/dev/disk/nata/ata-dma.c:90-154`: any tag-create /
   dmamem-alloc / map-load failure jumps to `error:` (line 149) which prints
   "WARNING - DMA allocation failed, disabling DMA", `kfree(ch->dma)`, and
   **sets `ch->dma = NULL`** (ata-dma.c:152-153). Attach *continues* — it does
   not abort the channel.
3. `ata_attach()` — `sys/dev/disk/nata/ata-all.c:111` (body around 126-130):
   `ATA_RESET(dev)` is called unconditionally for every channel.
4. `ATA_RESET` → `ata_pcichannel_reset()` — `sys/dev/disk/nata/ata-pci.c:841-851`:
   the DMA-engine reset is guarded by `if (ch->dma)` (842-847), but
   `ctlr->reset(dev)` (850-851) is called with **no guard**.
5. For AHCI, `ctlr->reset = ata_ahci_reset` (set at `ata-ahci.c:105`).
   `ata_ahci_reset()` — `sys/dev/disk/nata/chipsets/ata-ahci.c:466-469`:
   `work = ch->dma->work_bus + ATA_AHCI_CL_OFFSET;` — **unguarded NULL deref**
   (offset deref of a NULL `struct ata_dma *`) → kernel panic.

The same reset is also reached on resume / channel reinit
(`ata_reinit`, ata-all.c:187 → ATA_RESET), so the NULL must also survive any
later re-init after a failed alloc.

Sibling code is uniformly guarded: `ata-pci.c:791` (`if (ch->dma)`
alloc), `ata-pci.c:811` (`if (ch->dma)` free in detach), `ata-pci.c:842`
(`if (ch->dma)` in this very reset function) — the AHCI reset's unconditional
`ch->dma->work_bus` is the outlier.

## Expected behavior if triggered

`Fatal trap 12: page fault in supervisor mode` while accessing
`(struct ata_dma *)NULL + offsetof(work_bus)` during device attach / reinit —
boot-time or hot-plug-attach denial of service. No privilege impact; the
written value never reaches the fault (the fault is the first access).

## Fix

Guard the work-area setup (see fix.diff):

```c
if (ch->dma == NULL || ch->dma->work_bus == 0)
    return;
```

placed after the port-implemented check (ata-ahci.c:461-464), mirroring the
`if (ch->dma)` guards used by every sibling path.
