# DF-0867 — PoC: kernel panic via unvalidated rec_type in mirror_write_rec

## Claim (finding)
The HAMMER mirror-write record path accepts an on-disk `rec_type` without
validating it against the valid record-type set. A crafted mirror stream whose
record has `data_len > 0` and an unhandled `rec_type` reaches
`hammer_alloc_data()` (`sys/vfs/hammer/hammer_ondisk.c:1634`), whose `switch()`
only handles `INODE/DIRENTRY/EXT/FIX/PFS/SNAPSHOT/CONFIG/DATA/DB`; the default
case (`:1669`) calls `hpanic("rec_type %04x unknown", rec_type)` → kernel
panic.

## Reachability / threat model
- `HAMMERIOC_MIRROR_WRITE` ioctl is guarded by `caps_priv_check(cred,
  SYSCAP_NOVFS_IOCTL)` (`hammer_ioctl.c:72`) — root locally.
- Realistic remote vector: a malicious mirror *source* feeds a crafted
  mirror stream to a victim running `hammer mirror-write` on its HAMMER slave.
  The victim kernel parses the attacker-controlled stream and panics. No
  credentials on the target needed beyond what mirror-write already grants
  (a configured mirror relationship).
- This is a **memory-safe DoS** (the unhandled case panics before any write
  occurs; there is no write primitive). No escalation path.

## How to reproduce
```sh
# as root on the DragonFly guest:
./build.sh            # cc -o trigger trigger.c
./run.sh              # creates a HAMMER image, mounts it, fires the ioctl
```
Expected on the **unpatched** kernel: guest dies; `dfbsd-qemu/boot.log` shows
```
panic: rec_type 0002 unknown
```
(with `Stopped at hammer_alloc_data+...` / `db>`).

Expected on a **fixed** kernel: `trigger` returns cleanly, prints
`ioctl returned (no panic): head.error=...` (EINVAL), guest stays up.

## Files
- `trigger.c`        — minimal mirror-write mrec with bad rec_type
- `setup.sh`         — create+newfs+mount a HAMMER image (root)
- `build.sh` / `run.sh`
- `fix.diff`         — validate rec_type in hammer_ioc_mirror_write_rec
