# DF-0875 — hammer2_get_volume unconditional panic on out-of-range data_off

**Bug:** `hammer2_get_volume()` (`sys/vfs/hammer2/hammer2_ondisk.c:731-732`)
unconditionally `panic()`s when a blockref's `data_off` does not fall within
any mounted volume. A crafted HAMMER2 image with a valid-CRC volume header but
an out-of-range `sroot_blockset.blockref[0].data_off` triggers the panic on
mount. Impact: kernel DoS (panic). No write primitive → no escalation.

**Fix:** return NULL / propagate EIO instead of panicking. Validated on a
built and booted single-fix kernel.

## Reproduce

On the DragonFly guest as root:

```sh
./build.sh        # cc -O2 -o patch_image patch_image.c ; cc -O2 -o verify_image verify_image.c
./run.sh          # create image, newfs, corrupt data_off, fix CRCs, mount
```

**Expected on unpatched kernel:** panic — `panic: no volume for offset 0x0040000000000000`,
guest dead in DDB (check `dfbsd-qemu/boot.log`).

**Expected on fixed kernel:** `mount: Invalid argument` (EINVAL), guest stays
up. Dmesg shows `hammer2_get_volume: no volume for offset ...` (diagnostic)
followed by `hammer2_mount: error I/O Error reading super-root`.

## Files

| File | Description |
|------|-------------|
| `patch_image.c` | Image patcher: corrupts `data_off`, recomputes CRC32C (ICRC0/ICRC1/ICRCVH) |
| `verify_image.c` | Validates all three volume-header CRC32C values |
| `build.sh` | Builds the two tools |
| `run.sh` | Full reproduction: image → newfs → corrupt → mount |
| `fix.diff` | Validated fix (supersedes finding proposal) |
| `VERDICT.md` | Full analysis: mechanism, trace, fix, validation |
| `run.log` | Unpatched-kernel reproduction (panic signature) |
| `fix_run.log` | Patched-kernel validation (clean EINVAL, before/after contrast) |
| `fix_build.log` | Full single-fix kernel build log |
| `panic.txt` | Panic signature excerpt from `boot.log` |
| `env.txt` | Guest environment |
| `manifest.json` | Machine-readable artifact catalog |
