# DF-5576 — verdict narrative

## Finding
Interpreter treats unreachable states as panic() instead of errors: MS_OP_GET without an initialized mode loop (ppb_msq.c:292) and mode2xfer() unknown-mode/EPP-protocol panics (:70/:93/:101) — the latter also printing the wrong variable

## Bottom line (status: reproduced, impact: panic)
Reproduced on the QEMU guest (DragonFly 6.5-DEVELOPMENT x86_64), both variants, with production backtraces through ppb_MS_exec(). (a) MS_OP_GET with get_xfer[mode].loop == NULL panics at ppb_msq.c:292 instead of returning an error — vpoio_instr() (vpoio.c:461-476) reaches this exact ppb_MS_exec(MS_OP_GET) shape, and get_xfer slots are initialized for exactly ONE mode at attach (vpoio.c:612-633): any driver flow that reads before GET-init, or after the bus mode moved to an uninitialized slot, kills the kernel; the panic fires before the error path can run, so the 'error/abort' contract of the engine is unenforceable for reads. (b) mode2xfer() panics on any ppb->mode outside {0,1,2,4,8} (ppb_msq.c:100-102) — ppbconf.h itself defines mode aliases such as PPB_SPP=0x3 (ppbconf.h:47) that ppb_set_mode() stores verbatim after masking 0x0f (ppb_base.c:138); the harness sets exactly that alias and panics. The panic message also prints ppbdev->mode (the ivars field, 0 here) instead of the bus mode (3) — empirically demonstrated by 'panic: mode2xfer: unknown mode (0)' while the mode was 3. Reachability in-tree today requires a root-gated device node (ppi is 0600 root:wheel, ppi.c:164-166; vpo goes through CAM), so severity Low (robustness/local-DoS-class). Fix validated: GET-without-loop returns EOPNOTSUPP(45), unknown mode returns EINVAL(22) via NULL-from-mode2xfer handling in ppb_MS_init/ppb_MS_microseq; no panic, guest alive.

## Exploit chain
privileged device access (e.g. /dev/vpo0 flow that GETs in an uninitialized mode, or a future driver calling ppb_set_mode(PPB_SPP)) -> immediate kernel panic (local DoS); no memory-safety consequence

## Evidence
panic.get.txt (case 4: 'panic: ppb_MS_microseq: IEEE1284 read not supported', backtrace ppb_MS_microseq+0x244 <- ppb_MS_exec <- userland_sysctl); panic.mode.txt (case 5: 'panic: mode2xfer: unknown mode (0)' with the mode actually 3 — wrong-variable proof); fix_run.log ('DF-5576a returned 45 (no panic)', 'DF-5576b returned 22 (no panic)') on the patched production source

## Kernel references
- `sys/bus/ppbus/ppb_msq.c:292`
- `sys/bus/ppbus/ppb_msq.c:70`
- `sys/bus/ppbus/ppb_msq.c:93`
- `sys/bus/ppbus/ppb_msq.c:101`
- `sys/bus/ppbus/ppbconf.h:47`
- `sys/bus/ppbus/ppb_base.c:138`
- `sys/dev/disk/vpo/vpoio.c:469`
- `sys/dev/disk/vpo/vpoio.c:612`

## Fix validation (fixed)
GET-without-loop returns EOPNOTSUPP (was panic) and mode2xfer() returns NULL on unknown mode/protocol with EINVAL at both call sites (also retiring the wrong-variable panic message): case 4 -> 45, case 5 -> 22, no panic, guest alive.

`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; two fatal cases (4/5) driven one boot each with vm.sh resets between.

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.
