⬢ DragonFlyBSD Kernel Audit
DF-3067 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-3067",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "dos",
 "confidence": "certain",
 "verdict": "REPRODUCED on the stock INVARIANTS kernel (fresh vm.sh reset with-src): mounting a crafted HAMMER image whose undo FIFO is a 256KB ring of valid 8-byte PAD records (vol_version=6, first=next=UNDO|0x1000, alloc=UNDO|0x40000) makes hammer_recover_stage1s version-4 seqno backscan (hammer_recover.c:257-270) spin forever - PAD records are exempt from the seqno discontinuity check (:266-269), hammer_recover_scan_rev wraps at the zone base making the FIFO a ring (:789-790), and the loop has no byte counter or lap limit (the sibling fwd-scan bound is #if 0d at :312-335). Observed: mount never returns; 47,039+ rev scan_offset debug iterations captured while still running, first traced offset == crafted first_offset, ring wrap 3000000000000000->300000000003fff8 at iterations 513 and 33281, all 32,769 ring offsets revisited (lap>=2); the mounting thread burns 100% CPU in kernel mode and kill -9 pends forever (no cancellation points); vn0 stays wedged; guest otherwise alive. Read-only mount suffices; works on INVARIANTS and production kernels. Stage2 variant shares the root cause: its extended-range scan (:652-670) terminates only at ext_offset = the unvalidated REDO_SYNC.redo_offset u64 (:423-424). FIXED and validated: fix.diff bounds both backscan loops to one FIFO lap; on the rebuilt kernel #1 the identical image walks exactly one lap then fails the mount cleanly (recovery failure during seqno backscan -> Failed to recover HAMMER filesystem on mount), mount process exits, guest up; stock-image mount/RW cycle and hard-crash dirty recovery regressions all pass.",
 "exploit_chain": "",
 "evidence": [
  "bootlog_walk_trace.log: 47,039 hammer_recover_scan_rev: rev scan_offset ... console lines (still growing at capture), first offset 3000000000001000 == crafted first_offset",
  "run.log: walk wrap analysis - offset jumps UP 3000000000000000 -> 300000000003fff8 at iterations 513 and 33281 (hammer_recover.c:789-790 ring wrap); 32,769 distinct offsets = entire ring revisited; guest alive (fresh ssh answered PROBE_OK)",
  "fix_run.log (kernel #1 + fix.diff): one lap traced, then recovery failure during seqno backscan + Failed to recover HAMMER filesystem on mount, mount_hammer exits (zombie->reaped), guest up",
  "fix_build.log: make nativekernel KERNCONF=X86_64_GENERIC completed; kernel #1 Sat Sep 5 22:10:54 UTC 2026",
  "padflood.c: the forger - PAD-8 pattern {0xC84E,0x8040,8} flood + vol0_blockmap[3] patch (no vol_crc fixup needed, DF-3042)"
 ],
 "kernel_refs": [
  "sys/vfs/hammer/hammer_recover.c:250-270",
  "sys/vfs/hammer/hammer_recover.c:266-269",
  "sys/vfs/hammer/hammer_recover.c:312-335",
  "sys/vfs/hammer/hammer_recover.c:423-424",
  "sys/vfs/hammer/hammer_recover.c:652-670",
  "sys/vfs/hammer/hammer_recover.c:789-790",
  "sys/vfs/hammer/hammer_recover.c:901-930"
 ],
 "poc_changes": "Pass-2 author wrote the PoC from scratch (padflood.c) on the DF-3040 harness pattern (newfs_hammer base image + vol0_blockmap patch, no CRC fixup). Two iterations: (1) both packs initially shipped /root/run.sh causing an scp collision - the first guest run accidentally executed DF-3068s desync script (which reproduced DF-3068 immediately); renamed to run3067.sh/run3068.sh. (2) Shrank the PAD ring from the stock 512MB FIFO to 256KB (alloc=UNDO|0x40000) so the cyclic walks wrap is visible quickly in the debug trace.",
 "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": 2100,
 "guest_dirty": 0,
 "build_cmd": "sh build.sh (cc -O -o padflood padflood.c -I/usr/src/sys/vfs/hammer; truncate -s 12G + newfs_hammer -L uabase)",
 "run_cmd": "sh run3067.sh",
 "code_hash": "9dee8b15160f8fa2963263bf24c926c06bbf765cd9c89cc33cda337119e6f35f",
 "notes": "Dos/livelock class (not memcorrupt): the unbounded walk only reads FIFO buffers - no corruption, no escalation path identified. Unkillable spinning thread per mount attempt; vn device wedged until reboot. Same trust boundary as DF-0797/0798/0812/2594/3040 (mount of crafted image: root, or unprivileged with vfs.usermount=1). Guest was reset (with-src) after validation; guest_dirty=0 refers to the returned state.",
 "recommended_fix": "Bound the stage1 backscan and the stage2 extended-range scan to one FIFO lap (walked >= HAMMER_OFF_LONG_ENCODE(alloc_offset) -> EIO); see fix.diff",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sat Sep 5 22:10:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "Identical PoC image on the patched kernel walks exactly one lap then fails the mount cleanly (recovery failure during seqno backscan -> Failed to recover HAMMER filesystem on mount); mount process exits and is reaped; guest stays up. Stock-image regressions pass: mount/RW-create/sync/umount/remount cycle clean; hard-crash dirty recovery (reboot -q on mounted dirty fs) clean - recovery check seqno=0010014d, mount RC=0, all crash-surviving files intact.",
 "fix_evidence": "fix_run.log, fix_build.log (kernel #1 build), fix.diff"
}