# DF-0796 — NULL deref in `hammer2_inode_chain_and_parent`

**Finding:** `sys/vfs/hammer2/hammer2_inode.c:453` —
`hammer2_inode_chain_and_parent()` dereferences `chain->parent`
unconditionally, but `chain` can be NULL when the inode's cluster has a NULL
chain slot at `clindex` (an interior "gap" explicitly permitted by
`hammer2_vfsops.c:838`).  → kernel NULL-deref panic (local DoS).

**Severity:** Medium (CVSS 3.1 `AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H`,
CWE-476).

## Files

| file | purpose |
|------|---------|
| `df0796_harness.c` | KLD harness: synthesises a hammer2_inode with a NULL cluster slot and calls the vulnerable function |
| `Makefile` | `bsd.kmod.mk` build against `/usr/src/sys` |
| `build.sh` | builds `df0796_harness.ko` |
| `run.sh` | loads the module (panic on #0, SURVIVED on #1) |
| `fix.diff` | the verified one-hunk fix (early NULL return mirroring `hammer2_inode_chain()`) |
| `VERDICT.md` | full narrative: mechanism, reproduction, fix validation |
| `build.log` | full compiler output of the harness build |
| `run.log` | baseline (#0) run: panic signature |
| `panic.txt` | panic excerpt from `dfbsd-qemu/boot.log` |
| `fix_build.log` | full output of the single-fix `nativekernel` build |
| `fix_run.log` | before/after contrast on #0 vs #1 |
| `env.txt` | guest environment |
| `manifest.json` | machine-readable artifact catalog |

## Reproduce

The PoC must run **as root inside the DragonFly guest** (it loads a kernel
module).  Triggering the underlying bug from the unprivileged syscall
surface additionally requires a mounted HAMMER2 PFS with a gapped cluster
(degraded multi-volume slave); the harness reproduces that exact cluster
state deterministically without needing a crafted multi-volume image.

```sh
# on the guest, as root:
cd findings/poc/DF-0796
./build.sh                                  # -> df0796_harness.ko
./run.sh                                    # #0 kernel: panic (guest dies in DDB)
                                            # #1 kernel: "SURVIVED -- chain=0 parent=0"
```

## Expected output

**Bug present (unpatched `#0`):**
```
DF-0796: invoking hammer2_inode_chain_and_parent on inode with NULL chain slot (clindex=0, nchains=2)
Fatal trap 12: page fault while in kernel mode
fault virtual address   = 0x118
Stopped at hammer2_inode_chain_and_parent.cold.9+0x15:  movq 0x118,%rax
```
(`0x118` = `offsetof(hammer2_chain, parent)` from the NULL `chain`.)

**Fixed (`#1`):**
```
DF-0796: SURVIVED -- chain=0 parent=0 (bug is fixed or not present)
```
