# DF-2641 — PoC evidence pack (skipped: Low/hardening, latent sinks)

**Latent unguarded `chain->data` derefs in hammer2 xops backends — DF-2617
silent-NULL class, shadowed on every reachable path by earlier consumers.**

Sites (all in `sys/vfs/hammer2/hammer2_xops.c`):

- **:539** (`hammer2_xop_nrename`, ip4 target-directory type read): reads
  `chain->data->ipdata.meta.type` with **no `chain->error` check at all** —
  inconsistent with its siblings xops.c:386 / :630. Also :536-546 has no data
  guard. A chain with a live I/O/CHECK error (data NULL) faults at VA 0x50.
- **:403** (`hammer2_xop_unlink`): guarded only by `chain->error == 0`, which
  the DF-2617 primitive (data_off==0, chain.c:938) leaves at 0 with
  `chain->data == NULL`.
- **:664-678 and :691-721** (`hammer2_xop_nrename` adjust blocks): after
  `hammer2_chain_modify()` — which *succeeds* with `chain->data == NULL` for
  data_off==0 chains (chain.c:1467-1473 skips the load when
  `data_off & ~HAMMER2_OFF_MASK_RADIX` is 0) — `wipdata =
  &chain->data->ipdata; bzero(wipdata->filename, 256); bcopy(name2, …)` is a
  **write** variant faulting at the fixed address NULL+0x100.
- **:737** (iparent update): runs even when a prior step set `error != 0`,
  with no data guard.
- **:1618** (`hammer2_xop_inode_chain_sync`): post-modify
  `parent->data->ipdata.meta = xop->meta` — NULL write sink in the same
  function DF-0800 covers (DF-0800 is the parent==NULL variant at :1603).

**Why Low / not verified to crash on their own lines:** reaching any of these
with `chain->data == NULL` requires an in-memory inode (or a lookup result)
whose chain is corrupt. Every route there first passes (a) the
`hammer2_chain_dirent_test()` call sites at xops.c:282/368/610/771 — the
DF-2640 first-touch crash (verified: Fatal trap 12 in bcmp), or (b) the
frontend `hammer2_inode_get()` gdata read (inode.c:866). On multi-node
clusters the corrupt slave's backend crashes in the same dirent_test during
the nresolve that created the in-memory inode. So these lines are
defense-in-depth gaps that DF-2617's root fix (error on data_off==0) plus
DF-2640's dirent_test guards close at the source.

**Fix:** all of these sites are guarded by **DF-2640's verified `fix.diff`**
(same build, same regression run — see ../DF-2640/). Per the audit contract,
Phase V is skipped for Low/Info hardening findings; verdict below records
`untested` with this pointer.
