# DF-4342 VERDICT

**Status: inconclusive on this guest (finding stands on deterministic code reading)**
**reproduced: 0 · impact on this guest: none · confidence in the finding: certain**

## What was verified statically (deterministic, no hardware semantics assumed)

1. Two distinct hook names alias one channel:
   - E1: `chan = ffs(ts) - 1` (`if_mn.c:466-467`) — "ts2" and "ts2-3"
     both give `ffs(...)-1 == 2` (verified against `mn_parse_ts`,
     `if_mn.c:505-540`: "2-3" sets bits 2 and 3).
   - E1U: every valid hook hardcodes `chan = 1` (`if_mn.c:468-469`).
   - The netgraph core does not filter this: hooks are keyed by name only
     (`ng_add_hook` / `ng_findhook`, `sys/netgraph/netgraph/ng_base.c:697-763`).
2. The second `newhook` is admitted while the first is DOWN: the EBUSY
   branch tests `sc->ch[chan]->state == UP` (`if_mn.c:470-473`) — state DOWN
   falls through to `sc->ch[chan]->hook = hook;` (`:475`) overwriting the
   first hook's back-pointer while `hook1->private` still references the same
   `schan`, and `sc->nhooks++` (`:478`) counts a second owner.
3. Second connect is a silent success: `ngmn_connect` returns 0 early on
   `sch->state == UP` (`if_mn.c:664-665`) with no error to the caller.
4. First disconnect executes the full teardown regardless of the second
   hook (`if_mn.c:756-794`); the second disconnect early-returns BEFORE
   `sc->nhooks--` (`:756-758` vs `:795`) → permanent `nhooks` surplus.
5. Permanent admin DoS: `ngmn_config` gates every line change on
   `sc->nhooks > 0` (`if_mn.c:308-310`).
6. Double-free enabler: nothing serializes two concurrent
   `ngmn_disconnect` calls (DF-4341 evidence: `ng_disconnect_hook`
   `ng_base.c:839-858` takes no lock); both pass the `state == DOWN?`
   check at `if_mn.c:756` before either stores `DOWN` at `:758`; both then
   run the free loops `:779-794`. `mn_free_desc` overwrites `dp->vnext`
   with the freelist head (`:498-503`), so the loser's `dp2 = dp->vnext`
   (`:782`, `:792`) walks onto the global freelist and frees live
   descriptors belonging to other channels.

## Guest verification attempt

Same environment as DF-4341 (see env_guest.txt / run.log): no 0x110a PCI
device, `if_mn.c` is `optional mn netgraph` (not in GENERIC), no if_mn.ko,
`kldload` ENOENT — the `mn0` node cannot exist, so `trigger_alias.sh`
cannot run. Nothing was refuted; classification is **inconclusive** for the
on-guest reproduction while the logic defect itself is certain from source.

## Fix

`fix.diff` in this pack (ownership by `sch->hook != NULL` + clearing the
pointer at disconnect). `git apply --check` clean against the read-only
tree. Also closes the DF-1540 dangling-`sch->hook` read at the writer side.
Not buildable/testable on this guest (no hardware).

## Files

README.md, VERDICT.md, trigger_alias.sh, run.sh, run.log, env_guest.txt,
fix.diff, verdict.json, manifest.json

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
