{
  "finding_id": "DF-3252",
  "status": "untested",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Structural finding only (Low, DF-3208 ufs twin): ffs_vget inserts the inode into the unlocked per-mount ihash at ffs_vfsops.c:1120 before reading the dinode; on the bread error branch (:1134-1145, reachable from crafted images - ufs_lookup.c:480 passes directory-entry ino values to VFS_VGET with no range check, so ino_to_fsba can address past the device end) the creator marks the vnode VBAD and vx_puts it, and a concurrent ufs_ihashget waiter that blocked in vget while holding a reference receives the VBAD vnode with an all-zero dinode (i_mode 0, i_devvp NULL) as a successful VFS_VGET result. Materially weaker than the ext2 twin (DF-3251): ufs_vinits error branch is dead code (ufs_vinit returns 0 unconditionally - ufs_vnops.c:1954), the zeroed inode short-circuits ufs_inactive (ufs_inode.c:75 i_mode==0) and ufs_reclaim tolerates NULL i_devvp, so no memory-safety sink was identified; the escaped VBAD vnode violates the VFS_VGET contract and is cached/handed to namei callers. Note DF-0928 already covers the unlocked hash itself; this finding is the publish-before-validate ordering, not the missing lock.",
  "exploit_chain": "",
  "evidence": [
    "README.md (path:line analysis)"
  ],
  "kernel_refs": [
    "sys/vfs/ufs/ffs_vfsops.c:1120",
    "sys/vfs/ufs/ffs_vfsops.c:1134",
    "sys/vfs/ufs/ufs_ihash.c:105",
    "sys/vfs/ufs/ufs_lookup.c:480",
    "sys/vfs/ufs/ufs_vnops.c:1954",
    "sys/vfs/ufs/ufs_inode.c:75"
  ],
  "poc_changes": "",
  "attempts": 0,
  "guest_uname": "",
  "runtime_sec": 0,
  "guest_dirty": 0,
  "build_cmd": "",
  "run_cmd": "",
  "code_hash": "",
  "notes": "Would need a crafted FFS image plus a barriered lookup pair; DF-3190s crafted-FFS harness is the starting point.",
  "recommended_fix": "Move ufs_ihashins after the dinode bread succeeds (hash a VX-locked placeholder and remove it on error), or ufs_ihashrem + VBAD before vx_put on the error branch."
}