# DF-5574 — verdict narrative

## Finding
ppb_MS_microseq() MS_OP_PUT/GET handler recurses with no depth limit — a driver-registered transfer loop containing MS_OP_PUT exhausts the kernel stack (DOUBLE FAULT)

## Bottom line (status: reproduced, impact: panic)
Reproduced on the QEMU guest (DragonFly 6.5-DEVELOPMENT x86_64). ppb_MS_microseq()'s MS_OP_PUT/GET case recurses into itself twice per transfer (ppb_msq.c:301 initxfer, :309 xfer->loop) with no depth limit; the invariant that keeps this finite — 'the xfer microsequence should not contain any MS_OP_PUT or MS_OP_GET!' — exists only as a comment (ppb_msq.c:306-307). A transfer loop registered via ppb_MS_init() that itself contains MS_OP_PUT resolves to the same loop in mode2xfer() every level, so each recursion re-enters ppb_MS_microseq() one net frame deeper, forever. Harness case 2 registers exactly such a loop (through the production ppb_MS_init) and executes a two-instruction top sequence through the production interpreter: the unfixed kernel dies with 'DOUBLE FAULT - KERNEL STACK GUARD HIT!' / 'panic: double fault', RIP = module_base+0x340 inside ppb_MS_microseq (panic.txt). No in-tree driver currently registers a violating loop (vpo/imm register loop bodies of RASSERT_P/RFETCH_P/C_CALL instructions only), so reachability is a buggy/malicious KLD or future driver — severity Low, but the class is unbounded-recursion-to-corruption (CWE-674) in the interpreter's state machine. Fix validated: a re-entry guard (ppb->ppb_in_xfer around the two recursive calls, cleared on all exits) plus propagation of the recursive calls' return values (see DF-5577 — without it the guard's EINVAL was silently swallowed) turns the same case into 'rc=22 ret=119 maxdepth=1 (no crash)' with the guest fully alive; a legitimate multi-PUT top-level sequence still works because the guard is cleared between transfers.

## Exploit chain
KLD/buggy-driver registers put_xfer[mode].loop containing MS_OP_PUT -> any transfer on that bus recurses ppb_MS_microseq unboundedly -> kernel stack guard page -> DOUBLE FAULT panic (denial of service; the recursion writes only its own stack frames, so the primitive is stack-exhaustion, not controlled overwrite)

## Evidence
panic.txt ('DOUBLE FAULT - KERNEL STACK GUARD HIT!', 'panic: double fault', RIP=0xffffffff82600340 = msqhx module base + ppb_MS_microseq) from the baseline run; run.log (trigger lines); fix_run.log ('DF-5574 ppb_MS_microseq returned rc=22 ret=119 maxdepth=1 (no crash)') on the fix.diff-patched production source with the guest alive; build.log proves the pristine file was exercised

## Kernel references
- `sys/bus/ppbus/ppb_msq.c:296`
- `sys/bus/ppbus/ppb_msq.c:301`
- `sys/bus/ppbus/ppb_msq.c:306`
- `sys/bus/ppbus/ppb_msq.c:309`
- `sys/bus/ppbus/ppb_msq.c:312`
- `sys/bus/ppbus/ppbconf.h:156`

## Fix validation (fixed)
Re-entry guard (ppb->ppb_in_xfer) around the two recursive calls + return-value capture: the same case that DOUBLE-FAULTED now returns rc=22 (EINVAL) with maxdepth=1 and the guest stays alive; no legitimate in-tree flow is affected (guard cleared between transfers).

`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
No seed PoC existed. Case 2 originally demonstrated only the panic; the first guard fix exposed that the guard's EINVAL was discarded at the :309 call site (rc printed 0) — that discovery became DF-5577 and the fix was revised to capture the recursive return values.

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.
