# DF-4221 VERDICT — source-certain NULL-ccb deref on device-fed duplicate completion; HW(vmm)-gated, not live-reproducible on this guest

## Status: inconclusive (hardware/vmm-gated — no pvscsi device on the audit guest); defect certain at source level

## Root cause

`pvscsi_process_completion()`:

```
sys/dev/virtual/vmware/pvscsi/pvscsi.c:899   hcb = pvscsi_context_to_hcb(sc, e->context);
sys/dev/virtual/vmware/pvscsi/pvscsi.c:903   ccb = hcb->ccb;
sys/dev/virtual/vmware/pvscsi/pvscsi.c:908   ccb->csio.scsi_status = sdstat;      <-- NULL write
sys/dev/virtual/vmware/pvscsi/pvscsi.c:909   ccb->csio.resid = ccb->csio.dxfer_len - e->data_len;
sys/dev/virtual/vmware/pvscsi/pvscsi.c:911   if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { ... }
```

`e->context` is read from the completion ring, which is shared DMA with the
hypervisor device (`sc->cmp_ring`, filled by the device;
`pvscsi_process_cmp_ring` pvscsi.c:1051-1058 walks it under only the
assumption that the device behaves). `hcb->ccb` is NULL whenever the hcb is
not in flight:

* set NULL in `pvscsi_hcb_put()` (pvscsi.c:382) — called on every completion
  (pvscsi.c:1020) and on the `bus_dmamap_load_ccb` error path
  (pvscsi.c:1209);
* hcbs start on the free list with `ccb == NULL` (kmalloc M_ZERO +
  SLIST_INIT, pvscsi.c:1719-1720, 609-613).

The driver itself establishes that a not-in-flight hcb must be skipped — its
timeout handler does exactly that:

```
sys/dev/virtual/vmware/pvscsi/pvscsi.c:850-853
	if (ccb == NULL) {
		/* Already completed */
		return;
	}
```

The completion path lacks the same guard. A device that emits a completion
for (a) an already-completed context (duplicate) or (b) a never-issued
in-range context drives `ccb == NULL` into `ccb->csio.scsi_status = sdstat`
— a write to a fixed low address (first page unmapped on amd64) ⇒ page fault
⇒ panic. DoS, not controllable corruption: the write target is fixed by the
structure layout, not by the attacker.

## Why not DF-1455 (not a duplicate)

DF-1455 covers the *unvalidated context* (out-of-range `context` ⇒ wild
`sc->hcbs + (context - 1)` ⇒ OOB hcb) and the log2-derived ring masks. This
finding covers the *in-range context, idle hcb* case: a distinct missing
check (`ccb == NULL`), reached with a perfectly valid context value, on a
valid hcb pointer. Both defects live in the same function; the fixes are
independent and complementary (an in-range check alone does not fix this,
and my ccb guard alone does not fix DF-1455).

## Reachability analysis

* Attacker: the hypervisor/VMware host (device side of the paravirt ring).
  Same trust boundary already accepted by this audit for DF-1454 (device-fed
  sense length) and DF-1455 (device-fed context/log2).
* The driver ships in GENERIC (`sys/config/X86_64_GENERIC:147`,
  `sys/conf/files:3087`), so any DragonFly system on VMware ESXi/Fusion
  with a PVSCSI controller runs this code.
* Guest check performed: `pciconf -l` on the audit guest shows **no 15ad
  (VMware) PCI devices** — QEMU does not emulate pvscsi — so no live trigger
  is possible here (device-absent, not a false positive).

## Fix validation (on the audit guest's kernel source)

* Guest `/usr/src/sys/.../pvscsi/pvscsi.c` md5 `d3cfdba6fe7b03d200afcfaec291f544`
  == pristine host copy (fidelity record in `env.txt`).
* Baseline module build: OK (`build_baseline.log`).
* `fix.diff` applies with `patch -p2` (`patch_apply.log`) and the module
  rebuilds cleanly (`build.log`); the guard's new format string
  `"completion for idle context %llu ignored"` is present in the resulting
  `pvscsi.ko` binary — the patched path is compiled in.
* Runtime validation HW-gated (no device) ⇒ `fix_status: inconclusive`
  (compiles + applies; not exercised against hardware).

## Fix correctness notes

The guard returns without consuming/freeing anything: for an idle hcb there
is no ccb to complete, no DMA map to unload (any map was unloaded when the
real completion ran), and the callout is stopped harmlessly (idle hcbs have
no pending callout). The consumer index still advances in
`pvscsi_process_cmp_ring` (pvscsi.c:1057), so the ring makes progress — no
livelock. Combined with DF-1455's (recommended) in-range context check, the
completion path then handles every device-fed entry safely.

## 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.
