# DF-5577 — verdict narrative

## Finding
ppb_MS_microseq() discards the return value of its recursive self-calls: a mode-transfer loop that aborts on error is skipped and the whole MS_OP_PUT/GET reports success (error channel zeroed by initxfer's MS_RET(0))

## Bottom line (status: reproduced, impact: none)
Reproduced on the QEMU guest (DragonFly 6.5-DEVELOPMENT x86_64), discovered during DF-5574 fix validation when the guard's EINVAL vanished. At ppb_msq.c:301 and :309 the two recursive ppb_MS_microseq() calls have their return values discarded; the caller checks only its local `error`, which is the *ret side-channel written by MS_RET — and the initxfer run at :301 ends with MS_RET(0), zeroing `error` immediately before the transfer loop executes. Any abort inside the mode transfer loop (adapter exec_microseq failure — e.g. vpio's nibble_inbyte_hook timeout, an MS_OP_C_CALL error — or the DF-5574 guard) therefore propagates nowhere: the aborted transfer is skipped and the sequence continues to the next instruction, reporting success (harness: hook returns 5, top-level rc=0 and the following MS_RET overwrites ret with 0). For vpo/imm this means a timed-out or failed ZIP read/write mid-transfer is presented to the SCSI layer as a completed transfer over stale buffer contents — a silent data-integrity failure, not memory corruption. The top-level ppb_MS_exec() does propagate its own return value, which is why single-opcode failures surface but loop failures do not. Fix validated: capturing the recursive return value (xerr) and folding in the side-channel makes the same case return rc=5 with ret untouched (0x77) — 'failure propagated (fixed)' — and is the same change that makes the DF-5574 guard observable (rc=22).

## Exploit chain
root-gated ppbus device (vpo/imm) mid-transfer timeout -> error discarded at ppb_msq.c:309 -> vpio_instr() returns success -> SCSI/CAM consumes stale buffer data as a completed transfer (silent data corruption at the I/O layer)

## Evidence
run.log ('DF-5577 hook_failed=1 (rc=0 ret=0x0): FAILURE SWALLOWED - reported success (bug)') on pristine production code; fix_run.log ('DF-5577 hook_failed=1 (rc=5 ret=0x77): failure propagated (fixed)') on the fix.diff-patched source; the DF-5574 pack's v1-fix run ('rc=0' despite the guard tripping) documents the discovery

## Kernel references
- `sys/bus/ppbus/ppb_msq.c:301`
- `sys/bus/ppbus/ppb_msq.c:303`
- `sys/bus/ppbus/ppb_msq.c:309`
- `sys/bus/ppbus/ppb_msq.c:311`
- `sys/bus/ppbus/ppb_msq.c:317`
- `sys/dev/disk/vpo/vpoio.c:469`

## Fix validation (fixed)
Return values of the recursive ppb_MS_microseq() calls are captured (xerr) and folded with the *ret side-channel: the failing-loop case returns rc=5 (hook's error) instead of 0, and ret remains unwritten (0x77), proving the following MS_RET no longer runs after an aborted transfer.

`fix.diff` (sha256 8e3dfc90e6049ce1704c3cef833cba0904b6404f11360bdd299e37980e9327bb) carries all five ppb_msq.c fixes for this pass;
the hunks relevant to this finding are marked with its DF id in the comments.
Fix validation followed the family standard (cf. DF-5418): the fixed sources
were installed into the guest's `/usr/src/sys/bus/ppbus/`, the harness was
rebuilt (recompiling the production file), and the exact same case was
re-run — baseline vs patched outputs are in `run.log` / `fix_run.log`
(+ `panic*.txt`). The repo's `sys/` tree was never modified; the guest was
`vm.sh reset with-src` afterwards (sources restored+verified by snapshot).

## PoC changes vs seed
Found while validating the DF-5574 fix: the guard's EINVAL was swallowed (rc printed 0), which pinpointed the discarded return values at ppb_msq.c:301/:309. Case 6 added to demonstrate the pristine-code swallow directly (failing MS_C_CALL hook inside a registered loop).

Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64
Harness sha256: 4b728315b40157934f62c99e847f386b30202eef77083dc1a5c065b7b0448ded

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