# DF-3067 — PAD-only undo FIFO makes `hammer_recover_stage1`'s seqno backscan (and stage2's extended-range scan) unbounded — mount never terminates (livelock DoS)

Kernel: DragonFly 6.5-DEVELOPMENT #0 (X86_64_GENERIC, INVARIANTS), `sys/vfs/hammer`
File under audit: `sys/vfs/hammer/hammer_recover.c` (pass 2). New finding —
not DF-0812/DF-2594 (redo_data_bytes) nor DF-3040 (vol0_undo_array index).

## Root cause (hammer_recover.c)

* For **every version ≥ 4 mount** (stock images are version 7), stage1 runs a
  *seqno backscan* (`:257-270`): a `for(;;)` reverse FIFO walk whose only
  exits are an I/O/signature **error** or the first **non-PAD** record (to
  grab its `hdr_seq`). PAD records are explicitly exempt from the seqno
  discontinuity check (`:266-269`), and `hammer_recover_scan_rev` wraps the
  walk at the zone base (`:789-790`), making the FIFO a ring.
* An undo FIFO consisting solely of valid 8-byte PAD records
  (`{0xC84E, 0x8040, 8}` — self-consistent head==tail, no CRC required per
  `_hammer_check_signature:930`) defeats both exits: no error, no non-PAD.
  The loop has **no byte counter and no lap limit** → infinite loop at 100%
  CPU inside `mount(2)`. The disabled `#if 0` block at `:312-335` (a
  "grossly beyond last_offset" bound for the sibling forward scan) shows the
  author considered bounding these walks — it is compiled out.
* Same unbounded shape in stage2's extended-range scan (`:652-670`): it runs
  until `scan_offset == ext_offset` where `ext_offset =
  hmp->recover_stage2_offset` is `REDO_SYNC.redo_offset` — an **unvalidated
  u64** from the crafted record (`:423-424`); a garbage value that is not a
  reachable record boundary plus an all-PAD gap = same infinite loop (RW
  mounts).

## Threat model

Mount of a crafted HAMMER image (root, or unprivileged with
`vfs.usermount=1` — same precondition family as DF-0797/0798/0812/2594/3040).
A **read-only** mount suffices for the stage1 variant. The mount syscall
never returns; the mounting thread spins in kernel mode and cannot be killed
(the loop has no cancellation points), pinning a CPU and the vn device
forever. Works on INVARIANTS *and* production kernels (no assertion
involved).

## Reproduce

```
# guest (root): sh build.sh   (cc padflood.c; truncate 12G + newfs_hammer base)
sh run.sh
# expected:
#   padflood floods all undo bigblocks with PAD-8s, sets vol_version=6,
#   first=next=UNDO|0x1000, then:
#   MOUNTING ... (30s timeout) MOUNT_RC=124
#   ps: mount_hammer still present (unkillable, state R)
#   dmesg: thousands of "rev scan_offset 3000xxxxxxxxxxxx" lines cycling
#          down through the 1GB FIFO and wrapping - the unbounded walk
#   guest otherwise alive (other ssh commands keep working)
```

Success criterion: `MOUNT_RC=124` + unkillable mount process + cyclic
`rev scan_offset` debug flood + guest still up = reproduced (impact: dos).
