# DF-5348 VERDICT — REPRODUCED (phantom deferred load + callback on an unloaded map)

## Root cause

- `sys/sys/bus_dma.h:313` — `bus_dmamap_unload` expands to
  `_bus_dmamap_unload` only.
- `sys/platform/pc64/x86_64/busdma_machdep.c:1022-1031` —
  `_bus_dmamap_unload` frees active bpages and nothing else: it never
  removes the map from `bz->bounce_map_waitinglist`
  (busdma_machdep.c:651, the EINPROGRESS queueing site) and never resets
  `map->pagesneeded`/`map->pagesreserved` or releases the reservation
  taken by `reserve_bounce_pages` (busdma_machdep.c:1263).
- The ONLY dequeue path is `get_map_waiting()` (busdma_machdep.c:1408),
  driven by any bounce-page release (`free_bounce_page`:1399 /
  `return_bounce_pages`:1306) — even long after the driver aborted.
- `busdma_swi()` (busdma_machdep.c:1445) then executes the deferred
  `bus_dmamap_load` with the map's stashed `buf`/`buflen`/`callback`
  (queue-time values, busdma_machdep.c:647-649) and invokes the driver
  callback (busdma_machdep.c:804).

## Reproduced

KLD harness (POC_TEST=2), clean-boot DragonFly 6.5-DEVELOPMENT guest:

    mapY load -> 36 (EINPROGRESS; mapY queued, holds partial reservation of 1 bpage)
    bus_dmamap_unload(mapY) returned -- map is STILL on the waiting list
    bus_dmamap_unload(mapX) frees a bpage -> wakes the UNLOADED mapY ...
    *** DEFERRED CALLBACK FIRED FOR UNLOADED MAP *** buf=0xd0000002 nsegs=2 error=0
    RESULT=PHANTOM CONFIRMED

The callback fired for a transaction the driver had already unloaded; the
deferred load also bound a bounce page to the stale buffer (`datavaddr`)
inside the map.  With a driver that frees its buffer on abort (the normal
pattern) this becomes a write-after-free via the subsequent
`bus_dmamap_sync(PREWRITE/POSTREAD)` bounce copies
(busdma_machdep.c:1046, 1057).

## Impact

Concrete (demonstrated): driver-visible phantom callback after unload →
double completion of aborted transactions, stale-buffer DMA setup, and
leaked bounce-page reservations shrinking the shared zone (zone-exhaustion
DoS).  Driver-dependent worst case: write-after-free in whichever driver
uses the map, on any bounce-page release (attacker-groomable timing).

## Fix validation

Same fix.diff as DF-5347 (unload dequeues + releases reservation; busdma_swi
drops reset maps).  Patched kernel #1 (Oct 3 06:29): mapY's unload dequeues
it, the later page free wakes nothing:

    RESULT=FAILED      <- phantom callback did NOT fire (fix works)
    cleanup done

Guest stable.  Baseline behavior GONE.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
