# DF-2617 — PoC evidence pack

`hammer2_chain_load_data()` (sys/vfs/hammer2/hammer2_chain.c:938-939) treats
`bref.data_off == 0` as an early SUCCESS return for every blockref type, so
data-requiring types (INODE, INDIRECT, DATA, media DIRENT, FREEMAP_*) end up
with `chain->data == NULL` and `chain->error == 0`.  Every consumer that
trusts the (absent) error then dereferences NULL or wedges forever in the
debugging loop at chain.c:2524-2529.

Verified sinks (all from `mount`/`ls` of a crafted image, root):

| Variant | Corrupted bref | Observed (stock INVARIANTS kernel #0) |
|---------|----------------|----------------------------------------|
| P1 | volhdr sroot INODE `data_off=0` | **Fatal trap 12** at `hammer2_vfs_mount+0x1118: movq 0x90(%r8),%rax`, fault VA **0x90** (vfsops.c:1309/1311 super-root `ipdata.meta` read, right after the useless `schain->error` check at vfsops.c:1285) — panic.txt |
| P2 | PFS "testvol" INODE `data_off=0` (in sroot's blockset) | **Fatal trap 12** at `hammer2_pfsalloc+0x5ef: movzbl 0x87(%r13),%eax`, fault VA **0x87** = `ripdata->meta.pfs_type` (vfsops.c:1560-1561 PFS-label scan, guarded by a `chain->error` check that load_data never arms) — panic2.txt |
| H  | first INDIRECT under PFS root `data_off=0` | mount **succeeds**; `ls` wedges in the `while (1) tsleep(parent, 0, "xxx", 0)` loop at chain.c:2524-2529: serial shows `hammer2: unexpected NULL data on 0xfffff80119504500`; `ls` PID in state `D5`, wchan `h2coll`, **`kill -9` has no effect**; xop backend thread `h2xop-testvol.23` permanently asleep on wchan **`xxx`** — run_H.log, dmesg_H.txt |

## Reproduce

```sh
# guest (root): build the base image (newfs_hammer2 -L testvol + 33 files)
sh mkbase2617.sh                                   # -> base2617.img

# host: forge the three malformed images
python3 forge_df2617.py base2617.img P1 P1.img     # sroot data_off = 0
python3 forge_df2617.py base2617.img P2 P2.img     # PFS inode data_off = 0
python3 forge_df2617.py base2617.img H  H.img      # INDIRECT data_off = 0
# (push images + trigger_*.sh to guest:/root/poc/df2617/)

# guest (root), stock kernel:
sh trigger_P1.sh    # expect Fatal trap 12 in hammer2_vfs_mount  (panic.txt)
sh trigger_P2.sh    # expect Fatal trap 12 in hammer2_pfsalloc   (panic2.txt)
sh trigger_H.sh     # expect MOUNT_RC=0, then unkillable ls + kthread wchan 'xxx'
```

Success criteria (stock INVARIANTS kernel #0, uname in env.txt):
* P1/P2: `Fatal trap 12: page fault while in kernel mode` on the serial
  console with the addresses above.
* H: `hammer2: unexpected NULL data on <chain>` on console; `ls` process
  remains in `D5`/`h2coll` after `kill -9`; a `h2xop-*` kernel thread sits
  on wchan `xxx` forever; the mount is unusable.

With fix.diff applied (kernel #1) all three triggers fail *cleanly*
(kprintf + EINVAL mount failure / EIO readdir, no panic, no hang) and the
uncorrupted base image still mounts and lists normally (fix_run.log).

* Full narrative: **VERDICT.md**
* Machine verdict: **verdict.json** (schema: audit/persist_poc.py)
* Verified fix: **fix.diff** (git-apply-able; validated by guest rebuild)

Forger technique (from DF-2616/DF-2620): CHECK_NONE (methods=0x00) every
ancestor bref whose media block contains edited bytes, recompute the three
volume-header CRC32Cs of every on-disk volhdr copy.
