# DF-2583 — hammer2 image-forging PoC

## What this is

PoC for DF-2583: a malicious hammer2 filesystem image whose INDIRECT blockref
has an inflated `bref.data_off` radix triggers a kernel panic on default
DragonFlyBSD GENERIC (INVARIANTS ON) when a process `readdir`s the affected
directory. On a non-INVARIANTS kernel the same forged radix drives an
out-of-bounds read/write of the blockref array during flush
(`hammer2_flush.c:1094`).

## Build

```
./build.sh
```
Builds `forge` and `poc` with `cc -O2`.

## Setup (root, once per fresh guest)

```
sh setup_image.sh        # creates /root/h2.img (64 MB hammer2) with testdir
```

## Run (root runs the chain, the readdir itself runs as maxx)

```
sh run.sh                # default radix 17
# or: sh run.sh 20       # radix 20 (1MB)
```

`run.sh` does:
1. Forge `/root/h2.img` — patches the first INDIRECT bref's radix and
   recomputes the entire hammer2 CRC chain (XXH64 inode/indirect, CRC32C
   volume header).
2. `vnconfig` + `mount_hammer2` the forged image at `/mnt/h2test`.
3. `chmod 755 /mnt/h2test /mnt/h2test/testdir`.
4. Run `./poc /mnt/h2test/testdir` as unprivileged user `maxx` — calls
   `getdents(2)`, forcing the kernel to descend into the forged INDIRECT
   chain.
5. Cleanup (`umount`, `vnconfig -u`).

## Expected behavior

| Kernel | Result |
|--------|--------|
| unpatched (`#0`) | kernel panic at `hammer2_io.c:126` (`KKASSERT(pbase != 0 && ((lbase + lsize - 1) & pmask) == pbase)`); ssh dies, `db>` prompt in serial console |
| patched  (`#1`) | `getdents` returns `-1 errno=EDOM`; dmesg shows `hammer2_chain_load_data: ... forged radix ... rejecting chain`; guest stays up |

## Reproduce

```
./build.sh && \
[sh setup_image.sh] && \
sh run.sh
```

The setup is needed only once. `run.sh` will re-forge the image each time
(the forge is idempotent on an unforged image; if you re-run on an
already-forged image, re-run `setup_image.sh` first to reset it).
