# DF-4536 — VERDICT

**Status: not_reproduced** — the driver-level TOCTOU exists
(`sys/dev/misc/lpt/lpt.c:458-462`, unsynchronized check-then-set), but
on this tree it cannot manifest: every lpt cdev operation runs under
the kernel mplock because lpt's `dev_ops` head flags are 0
(lpt.c:191-198) → `dev_needmplock()` true (sys/kern/kern_device.c:119)
→ `dev_dopen()` wraps `d_open` in Giant (sys/kern/kern_device.c:142).
Two concurrent lptopen() entries are impossible as configured, so the
double-kmalloc/double-kfree consequence is unreachable today.  Filed
at Info as a latent defect: converting lpt to D_MPSAFE without first
adding per-unit serialization re-opens the window with a heap
double-free payoff.

## Attempts (guest, root, fd-hold detection so sequential pairs cannot false-positive)

| race configuration | rounds | hits |
|---|---|---|
| `/dev/lpt0` × `/dev/lpt0` (same vnode, full path) | 300 | 0 |
| `/dev/lpt0` × `/dev/lpt0.ctl` (different vnodes/cdevs) | 300 | 0 |
| `/dev/lpt0.ctl` × `/mnt/df2/lpt0.ctl` (two devfs mounts) | ~3,600 | 0 |

The last configuration removes both the shared vnode lock and any
same-cdev devfs serialization; only the mplock remains — proving the
mplock is the operative serializer.

Note on methodology: an early run without the fd-hold printed many
"both opens returned 0" — these were sequential (sibling opened after
the first closed, state already cleared), *not* races.  The released
PoC holds each fd 300 ms (configurable), making sequential
double-success impossible; with that fix all configurations score 0.

## Fix

`fix.diff`: per-unit `spinlock sc_openlk` in `struct lpt_data`;
serialize the open state transition and the close-time buffer frees
(+ NULL-ing).  git-apply-clean against the tree.  Runtime fix
validation not applicable (nothing to observe on a non-manifesting
bug).

## Kernel references

- sys/dev/misc/lpt/lpt.c:458-462 (unsynchronized check-then-set)
- sys/dev/misc/lpt/lpt.c:538-541 (second open's kmallocs overwrite sc_inbuf)
- sys/dev/misc/lpt/lpt.c:598-599 (both closes kfree the same pointer)
- sys/dev/misc/lpt/lpt.c:191-198 (dev_ops flags 0)
- sys/kern/kern_device.c:119-122 (dev_needmplock)
- sys/kern/kern_device.c:142-156 (dev_dopen mplock wrap)

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