DF-4895 / verdict.json
{ "finding_id": "DF-4895", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Deterministic privileged-local kernel panic reproduced 1/1 on the QEMU guest: complete_raid5_write() launches RAID-5 second-phase I/O via vn_strategy(drive->vp) (vinuminterrupt.c:427/:464) while drive->vp can be NULL (daemon close_locked_drive after set_drive_state down) or mid-vn_close (vnode UAF window). First-phase I/O survives the same teardown because it uses the cdev (dev_dstrategy, vinumrequest.c:436); only the second phase is vp-coupled. Trigger: vinum stop -f d2 (real teardown), state pokes back up, one 32KB group write -> Fatal trap 12 at vn_strategy+0x38 (testb $0x40,0x5c(%r13) = vp->v_flag deref of NULL), current process dd. fix.diff (dev_dstrategy via the already-set bio_driver_info at both sites) validated on a rebuilt kernel: identical trigger completes cleanly, second-phase data verifiably lands on the raw device through the cdev route, RAID-5 roundtrip intact.", "exploit_chain": [ "root: vinum stop -f d2 -> set_drive_state(down, force) -> queue daemonrq_closedrive -> daemon vn_close(drive->vp), vp=NULL (or, in the ENXIO error path, complete_rqe:129-139 does this and immediately continues into complete_raid5_write in the same call)", "root: vinum setstate -f up d2 + sds/plex/vol (setstate_by_force pokes states; vp stays NULL) \u2014 mirrors any admin recovery that does not re-init the drive", "any volume write: bre5 builds normal RMW group (sd states up); launch_requests fires first-phase reads via cdev (valid) -> complete_rqe -> complete_raid5_write -> vn_strategy(NULL) -> fatal trap 12", "mid-flight variant (no state pokes needed): group write built while drive up, daemon vn_close lands between first and second phase -> strategy on closing/closed vnode -> vnode use-after-close (memory-corruption potential)" ], "evidence": "panic.txt (serial console: Fatal trap 12 ... fault virtual address = 0x5c ... Stopped at vn_strategy+0x38: testb $0x40,0x5c(%r13), process dd); run.log (baseline transcript incl. offset-mapping proof 0xAA->md1s0:425/4521); run.patched.log (fix validation: no panic, 0xCC lands at both offsets, ROUNDTRIP OK); fix_build.log; fix.diff", "kernel_refs": [ "sys/dev/raid/vinum/vinuminterrupt.c:427", "sys/dev/raid/vinum/vinuminterrupt.c:464", "sys/dev/raid/vinum/vinuminterrupt.c:194", "sys/dev/raid/vinum/vinuminterrupt.c:129", "sys/dev/raid/vinum/vinumstate.c:87", "sys/dev/raid/vinum/vinumstate.c:942", "sys/dev/raid/vinum/vinumio.c:225", "sys/dev/raid/vinum/vinumrequest.c:436", "sys/kern/vfs_bio.c:3375" ], "poc_changes": "Trigger developed during verification (no seed). v1 (flap racer: writers + setstate -f down/up loop) failed: CLI vinum setstate -f goes to setstate_by_force() which pokes DRIVE[].state directly and never calls set_drive_state/never queues the daemon close \u2014 proven live (writes kept landing on the down drive). v2 (vinum stop d2 non-forced) refused EBUSY: opencount (attached-subdisk count, never decremented) is always nonzero for a drive hosting sds. v3 (final): vinum stop -f d2 is the only CLI route to set_drive_state(down, force) -> daemon really vn_closes vp (state cascade visible in dmesg) -> deterministic panic on the next group write after state pokes.", "attempts": 3, "guest_uname": "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", "runtime_sec": 1500, "guest_dirty": 0, "build_cmd": "cd /usr/src && git apply fix.diff && make -j6 quickkernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC", "run_cmd": "sh setup_vinum.sh && sh trigger.sh (expect: Fatal trap 12 vn_strategy+0x38; patched: SURVIVED + data lands)", "code_hash": "cb9fe6b5a627bdfa975548cb25d4b664059873da7c8e56119c59b14952f41965", "notes": "Fix validated: baseline panic 1/1, patched 0/1 with the fixed path proven exercised (raw-device pattern check). sdio() (vinumrequest.c:980) has the same vn_strategy(drive->vp) pattern \u2014 same fix needed there (separate file). Patched-guest shutdown after the deliberately corrupted admin state needed vm.shs force-kill path (same as baseline resets); no panic signature. Guest reset to with-src snapshot after validation.", "recommended_fix": "Launch second-phase RAID-5 I/O via dev_dstrategy(rqe->b.b_bio1.bio_driver_info=cdev) exactly like the first phase, at vinuminterrupt.c:427 and :464 (see fix.diff); apply the same to sdio() in vinumrequest.c:980.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Rebuilt kernel with fix.diff: identical deterministic trigger no longer panics; second-phase writes verifiably reach the raw device through the cdev route (pattern 0xCC at md1s0 sectors 425 and 4521); 32KB RAID-5 roundtrip still correct. Bug considered fixed by this diff.", "fix_evidence": "run.patched.log, fix_build.log, fix.diff" } |