# DF-0855 — dirfs_findfd KKASSERT panic / NULL deref on unlinked dirfs nodes

## Summary
`dirfs_findfd` (`sys/vfs/dirfs/dirfs_subr.c:479-480`) uses
`KKASSERT(dnp1 != NULL)` after `dnp1 = dnp1->dn_parent`, which panics when
the node has been unlinked (`dn_parent == NULL`). The sibling function
`dirfs_node_absolute_path_plus` handles the same NULL-parent case correctly
(`if (dnp1 == NULL) break;`), proving the guard was simply omitted from
`dirfs_findfd`.

**Trigger**: `open /mnt/f; unlink /mnt/f; fstat(fd)` →
`VOP_GETATTR → dirfs_getattr → dirfs_findfd` on the unlinked node →
`KKASSERT(dnp1 != NULL)` panic.

**dirfs is vkernel64-only** (not in `sys/conf/files`; 3 entries in
`sys/platform/vkernel64/conf/files` as `optional dirfs`). The running
X86_64_GENERIC host kernel does not include it. A deterministic harness
transcribes the buggy code path and proves the panic; the fix is
compile-validated.

## How to reproduce
```
ssh dfbsd-maxx
cd poc/DF-0855
./build.sh && ./run.sh
```

**Expected**: `DF_0855_BUG_PANIC_ON_UNLINKED_NODE = YES` and
`DF_0855_FIX_RETURNS_NULL_NO_PANIC = YES`, exit 0.

## Fix
`fix.diff` — replace `KKASSERT(dnp1 != NULL)` with `if (dnp1 == NULL) break;`
in `dirfs_findfd` (mirroring `dirfs_node_absolute_path_plus`), plus a NULL
guard in `dirfs_getattr` returning ESTALE.

## Files
- `harness.c` — deterministic transcription of dirfs_findfd + unlink setup
- `build.sh` / `run.sh` — build and run wrappers
- `fix.diff` — git-apply-able unified diff (2 hunks)
- `VERDICT.md` — full analysis
- `build.log` / `run.log` / `run.stress.log` — full logs
- `fix_build.log` — compile-neutral validation
- `env.txt` — guest environment
- `manifest.json` — artifact catalog
