DF-4423 / verdict.json
{ "finding_id": "DF-4423", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED on DragonFly 6.5-DEVELOPMENT/X86_64_GENERIC (private KVM guest, vtblk0 as non-root 256MB data disk, detach driven via a helper KLD calling device_detach() = the exact vtblk_detach() path of kldunload/unplug). 96 threads x one 2MB pread (192MB) were mid-flight when vtblk_detach() ran at t=5s: every pread returned full success at the detach instant (errors=0, read_ms ~5000ms for all threads) while QEMUs own block counters show the device transferred only 17,956,864 of the 201,326,592 bytes (8.9%). The other 185MB (91%) of successfully read data was fabricated by vtblk_drain()/strategy-ENXIO completing bios with biodone() without setting B_ERROR/b_error (virtio_blk.c:1202-1207 drops the error argument); userspace received recycled kernel buffer/page contents (stale physical memory from previous boots - leak samples show 0xAA fill and 0x5A marker patterns the device never transferred in the window). Consequences: silent data corruption (unperformed reads/writes reported complete to the fs layer) plus stale-kernel-memory disclosure to any reader of the device. Controls: identical volley without detach = 100% real data (95.81s cold-cache), and the classifier was validated against direct dd+hexdump reads. Not a UAF: post-detach reads error cleanly (EBADF), so the known DF-1605 family did not pollute the run.", "exploit_chain": "", "evidence": "run_ks2.out (per-thread timing: all read_ms ~4900-5050ms = released exactly at the 5s detach; RESULT ... errors=0), blockstats_s0.txt/blockstats_s1.txt (QEMU rd_bytes delta 17,956,864 vs 201,326,592 guest-visible success bytes), leak_sample_0.bin (0xAA fill pattern) / leak_sample_1.bin (0x5A marker pattern) = fabricated data, env_dmesg.txt (detach trace), VERDICT.md for the full narrative including the 95.81s no-detach control.", "kernel_refs": [ "sys/dev/virtual/virtio/block/virtio_blk.c:1202", "sys/dev/virtual/virtio/block/virtio_blk.c:1078", "sys/dev/virtual/virtio/block/virtio_blk.c:1103", "sys/dev/virtual/virtio/block/virtio_blk.c:532", "sys/dev/virtual/virtio/block/virtio_blk.c:543" ], "poc_changes": "Seed concept (unload driver mid-I/O) had to be rebuilt entirely: virtio_blk is compiled into the audit kernel (kldunload impossible) and DragonFly has no PCI/ACPI hotplug handling (QEMU device_add ignored), so detach was driven by a 30-line helper KLD invoking device_detach() on vtblk0 from a private QEMU instance whose root is on IDE. Tester gained: per-chunk classification (fixed a signed-char comparison bug found via the control run), per-thread CLOCK_MONOTONIC timing, leak-sample dumps, marker mode, and a QEMU blockstats delta protocol to separate real DMA from fabricated completions (host/guest cache made naive garbage bytes checks unreliable).", "attempts": 9, "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": 5400, "guest_dirty": 0, "build_cmd": "cc -O2 -pthread -o df4423_tester df4423_tester.c && (kmod dir) make # dfdetach.ko via bsd.kmod.mk", "run_cmd": "sh /root/killshot2.sh # 96x2MB pread volley + device_detach at t=5s; QEMU info blockstats before/after", "code_hash": "4daf70c2ffc79d9278dc6e2ff7227527d0044d08993c4861337cd3b25b6475fe", "notes": "Private-VM setup documented in VERDICT.md (IDE root + 256MB virtio test disk; loader vfs.root.mountfrom override). Write-path variant (silently lost writes) follows from the same drain path; read variant chosen because fabricated data is directly observable. Main audit guest untouched (overlay discarded).", "recommended_fix": "vtblk_finish_bio(): set bp->b_flags|=B_ERROR, bp->b_error (if unset) and bp->b_resid=bp->b_bcount when error!=0, before biodone()", "fix_status": "not_testable", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored from the line-accurate trace; single-fix kernel rebuild not exercised in this run (non-memory-corruption class). Baseline (buggy) behavior reproduced and fully quantified above.", "fix_evidence": "fix.diff" } |