# DF-3302 VERDICT — NOT REPRODUCED (race real, window nanoseconds)

## Bottom line
`add_mfc()` calls `mfc_find()` at `ip_mroute.c:976` **before** taking
`mroute_token`; the returned `rt` is used under the token at `:986-988`
(`update_mfc_params(rt, ...)` writes `rt->mfc_parent`, `rt->mfc_ttls[]`,
`rt->mfc_flags[]`). A concurrent `MRT_DEL_MFC` on another CPU takes the
token, unlinks and `kfree`s the same entry (`:1095-1117`) between the
unlocked lookup and the update → write into freed memory.

Guest run: 512 colliding (S,G) pairs (bucket 54) to lengthen the
`mfc_find` walk, two threads hammering ADD_MFC vs DEL_MFC for 100 s:
`survived 100 seconds (no INVARIANTS trip / panic)`. The window between
lookup-return and token acquisition is nanoseconds; kfree under DF's
objcache does not poison freed chunks, so a silent UAF-write lands only
with extreme luck. Race is certain from the code; manifestation not
landed → `not_reproduced`, impact none demonstrated.

Both racing operations are root-only sockopts (raw IGMP socket), so the
practical severity is Low regardless.

## Fix (in fix.diff; validated kernel builds and boots)
Take the token before the lookup and keep it across the update:
```diff
+    lwkt_gettoken(&mroute_token);
     rt = mfc_find(...);
     if (rt) { update_mfc_params(rt, mfccp);
-	lwkt_gettoken(&mroute_token);
-	update_mfc_params(rt, mfccp);
 	lwkt_reltoken(&mroute_token); return 0; }
```
(the redundant second gettoken later in the function becomes a no-op for
a recursive token but is removed in fix.diff for clarity).

## 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.
