{
  "finding_id": "DF-3068",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED twice on the stock INVARIANTS kernel (second run after a fresh vm.sh reset with-src, clean sequence): mounting a crafted version-3 HAMMER image whose vol0_blockmap[3] names an 8-byte nominal undo range (first=UNDO|0x1000, next=UNDO|0x1008) containing a fake tail {0xC74F,0x0041,24} at 0x1000 that anchors a CRC-valid 24-byte DUMMY head at 0xff0 makes hammer_recover_stage1's undo loop consume 24 bytes where 8 remain (bytes -= hdr_size, hammer_recover.c:431) and KKASSERT(error || bytes == 0) at :460 panics: 'panic: assertion \"error || bytes == 0\" failed in hammer_recover_stage1 at hammer_recover.c:460', trace hammer_recover_stage1 <- hammer_vfs_mount <- sys_mount, guest wedged at db>. Root cause: hammer_check_tail_signature positions the head via the TAIL's size (:1023-1026) while hammer_recover_scan_rev steps via the HEAD's hdr_size (:815), and _hammer_check_signature never requires tail/head size agreement for PAD/DUMMY-style short records (:901-924 skip, :948-961 re-derive) - version<4 mounts take next_offset verbatim (:225-226). On production (non-INVARIANTS) kernels the assert is absent: the mount silently succeeds, executes a record from outside the nominal undo range, and rewrites+flushes the volume-header blockmap (:481-488) - silent mis-recovery, no memory unsafety (undo copies clamped at :1053-1076), hence Low severity. FIXED and validated: fix.diff adds hdr_size>bytes -> EIO guards in stage1's undo loop and stage2's fwd loop; on the rebuilt kernel #1 the identical image yields 'HAMMER(uabase) Corrupt UNDO record size 0018 at 3000000000000ff0' + 'mount: Input/output error', no panic, guest up; stock regressions (mount/RW cycle, hard-crash dirty recovery) all pass.",
  "exploit_chain": "",
  "evidence": [
    "panic.txt (clean run): 'HAMMER(uabase) recovery undo  3000000000001000-3000000000001008 (8 bytes)(RW)' then 'panic: assertion \"error || bytes == 0\" failed in hammer_recover_stage1 at /usr/src/sys/vfs/hammer/hammer_recover.c:460' with trace hammer_recover_stage1 <- hammer_vfs_mount <- sys_mount <- syscall2, guest at db>",
    "panic_console_full.txt: first (accidental) run - identical panic, proving determinism",
    "run.log: padflood desync craft output - 'DUMMY+fake-tail written at phys 0000000001088000 + ff0', 'undo AFTER first=3000000000001000 next=3000000000001008', 'vol_version=3 mode=desync crafted OK'",
    "fix_run.log (kernel #1 + fix.diff): 'Corrupt UNDO record size 0018 at 3000000000000ff0' + 'mount: Input/output error' MOUNT_RC=1, no panic, guest up; plus stock regressions",
    "fix_build.log: make nativekernel KERNCONF=X86_64_GENERIC completed (kernel #1)"
  ],
  "kernel_refs": [
    "sys/vfs/hammer/hammer_recover.c:225-226",
    "sys/vfs/hammer/hammer_recover.c:393-431",
    "sys/vfs/hammer/hammer_recover.c:460",
    "sys/vfs/hammer/hammer_recover.c:814-815",
    "sys/vfs/hammer/hammer_recover.c:901-924",
    "sys/vfs/hammer/hammer_recover.c:948-961",
    "sys/vfs/hammer/hammer_recover.c:1023-1026"
  ],
  "poc_changes": "Pass-2 author wrote the PoC from scratch (padflood desync mode). The DUMMY's tail bytes double as the next fake tail so one 24-byte record satisfies both the real-tail and fake-tail decodes; CRC computed as crc32(head[0..12)) ^ crc32(bytes[16..24)) per hammer_crc_get_fifo_head. Version patched 7->3 so the nominal range comes straight from the crafted blockmap; no vol_crc fixup needed (DF-3042).",
  "attempts": 2,
  "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": "sh build.sh (cc -O -o padflood padflood.c -I/usr/src/sys/vfs/hammer; truncate -s 12G + newfs_hammer base image)",
  "run_cmd": "sh run3068.sh",
  "code_hash": "9dee8b15160f8fa2963263bf24c926c06bbf765cd9c89cc33cda337119e6f35f",
  "notes": "Deterministic INVARIANTS-only panic (dos bucket); production kernels silently mis-recover instead - no memory corruption, all undo copies bounds-checked. Sibling asserts reachable via the same desync: :394, stage2 :698/:716, and the rterm KKASSERT at :1286. Same trust boundary as the rest of the hammer crafted-image family (root mount or vfs.usermount=1). Guest reset (with-src) after validation.",
  "recommended_fix": "Reject records whose hdr_size exceeds the remaining recovery bytes (EIO) in stage1's undo loop and stage2's forward loop before executing them; 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 on the patched kernel: the new guard fires at exactly the crafted record ('Corrupt UNDO record size 0018 at 3000000000000ff0'), mount fails with I/O error, no panic, guest stays up (vm.sh status: up). Stock regressions pass incl. hard-crash dirty recovery.",
  "fix_evidence": "fix_run.log, fix_build.log (kernel #1 build), fix.diff"
}
