# DF-5061 — ida_v4_done() empty-FIFO sentinel is dead code on LP64 → wild kernel pointer deref

File under audit: `sys/dev/raid/ida/ida_pci.c` (pass 2), lines 101–111.

## TL;DR

`ida_v4_done()` tests `if (completed == -1)` where `completed` is
`bus_addr_t` (**uint64_t** on x86_64, `sys/cpu/x86_64/include/bus_dma.h:36`)
but is assigned from `ida_inl()` = `bus_space_read_4()` which returns
**u_int32_t** (`sys/cpu/x86_64/include/bus_dma.h:130`). The 42xx board's
empty-reply-FIFO value `0xFFFFFFFF` zero-extends to `0x00000000FFFFFFFF`,
which never equals `0xFFFFFFFFFFFFFFFF` — the "fifo is empty" check is
**dead code on every 64-bit DragonFly**. Both consumers then treat the
empty FIFO as a completion:

* `ida_wait()` (`ida.c:457-467`, the polling path taken by *every*
  `ida_command()` during attach while interrupts are disabled) exits its
  poll loop instantly with `completed = 0xFFFFFFFF`;
* `ida_intr()` (`ida.c:482-491`) enters its drain loop for the same value
  and would spin forever printing `ignoring completion ffffffff`.

Both feed the value to `idahwqcbptov()` (`ida.c:140-148`), which computes
`hwqcbs + (0xFFFFFFFC - hwqcb_busaddr)` — with DMAP-mapped `hwqcbs` and its
32-bit physical `hwqcb_busaddr` this cancels to exactly **DMAP + 0xFFFFFFFC
(physical 4 GB − 4)** — and **dereferences** `hwqcb->qcb`. On any host with
< 4 GB RAM that is an unmapped DMAP page → kernel page fault. The driver
ships in the GENERIC kernel (`device ida`, `X86_64_GENERIC:132`), so a v4
board (Compaq Integrated Array / RAID LC2 / SA4200 / SA4250ES / SA431)
panics the machine **during boot attach**.

## The PoC (harness KLD)

`df5061_harness.c` runs **verbatim copies** of `ida_v4_done()`
(ida_pci.c:101-111) and `idahwqcbptov()` (ida.c:140-148) against a mock
32-bit MMIO register file whose `R_42XX_REPLY` slot holds `0xFFFFFFFF` —
exactly what a 42xx board presents on an empty reply FIFO. Every byte of
kernel-side logic (types, macros, arithmetic, deref) is the shipping
driver's code; only the board's register file is mocked.

## Build

    # on the DragonFly guest (source in /usr/src)
    sh build.sh            # -> /tmp/df5061/df5061.ko   (see build.log)

## Run

    kldload /tmp/df5061/df5061.ko
    sysctl hw.df5061_mode=1   # fixed variant: sentinel honored -> returns 0
    sysctl hw.df5061_fire=1   # SAFE run  (run.log / fix_run.log)
    sysctl hw.df5061_mode=2   # verbatim driver code -> wild deref
    sysctl hw.df5061_fire=1   # KERNEL PANIC (panic.txt)
    # (mode 3 prints the wild-pointer arithmetic without dereferencing;
    #  note idahwqcbptov() itself must deref hwqcb->qcb to return, so even
    #  mode 3 faults — which is itself the proof that the driver cannot
    #  even *compute* the qcb without touching wild memory.)

## Expected

* mode 1: `ida_v4_done_fixed() = 0` — empty FIFO detected, no side-effect
  register write, no fault.
* mode 2/3: `Fatal trap 12: page fault while in kernel mode`,
  `fault code = supervisor read data, page not present`, faulting
  instruction = the `hwqcb->qcb` load (`movq 0x110(%rax,%rdx,1),%r13`),
  fault VA == `hwqcbs + (0xFFFFFFFC - hwqcb_busaddr) + 0x110`.

## Fix validation

* `fix.diff` (git-apply-able against `sys/`) masks the sentinel compare:
  `if (completed == (bus_addr_t)0xffffffffU)`.
* Patched real driver rebuilt clean (`ida.ko`, `-Werror`) — `fix_build.log`.
* Fixed variant re-run on guest: sentinel works, no fault — `fix_run.log`.

## Hardware gate (honest limits)

The guest has no Compaq SMART controller (`pciconf -l`: no 0e11 devices),
so the *device* path cannot run end-to-end in QEMU. The mock-register
harness executes the driver's own kernel-side code path verbatim; the
types/arithmetic/deref are identical to a real board returning
`0xFFFFFFFF` on an empty reply FIFO.
