# DF-3032 — VERDICT

**Status: untested (skipped by policy — Low severity, speculative race)**
**Defect: present in code (certain). Exploitability: speculative (race window).**

## Static proof

* `ext2_vnops.c:749-763`: for a directory source, `ip->i_flag |= IN_RENAME`
  (`:760`) before `vn_unlock(fvp)` (`:799`).
* `ext2_vnops.c:976`: `relookup(fdvp, &fvp, fcnp)` can return a *different*
  inode (`xp = VTOI(fvp)` at `:1012`) than the `ip` the flag was set on.
* `ext2_vnops.c:1025-1031`: the `xp != ip` branch is empty by design ("we
  can't panic here" — contrasting with `sys/vfs/ufs/ufs_vnops.c:1199-1203`
  which panics for directories).
* `:1079` (`xp->i_flag &= ~IN_RENAME`) executes only in the `else`
  (xp == ip) branch; `:1094`/`:1098` execute only via `bad:`/`out:`.
  The `xp != ip` success path returns at `:1086` with the flag still set.
* Consumer of the stale flag: `ext2_vnops.c:754-755` — every future rename
  with this directory as source returns `EINVAL` until the inode is reclaimed
  (`ext2_reclaim` frees the in-core inode).

## Impact ceiling

One directory per won race becomes unrenameable until unmount/reboot.  No
memory-safety consequence (flag only gates the `:755` EINVAL and the `:755`
family of checks).  On-disk state stays consistent; hence Low/speculative.

## Why no guest run

Winning the race requires a purpose-built harness (two CPUs renaming into the
same slot in a tight loop) and even then success is probabilistic; for a Low
logic bug this is out of proportion.  If desired, the fix can be validated by
code inspection: the one-line clear is sufficient because nothing else reads
IN_RENAME between `:760` and the return.

## Recommended fix

`fix.diff` — clear `IN_RENAME` on `ip` in the `xp != ip` branch when
`doingdirectory`.
