# VERDICT — DF-2782: sys_mq_open NULL-pointer lockmgr panic (race-gated limit path)

**Status: REPRODUCED** · impact: panic · confidence: certain

## What was proven on the guest (stock kernel, build #0)

`/tmp/limit_race 300` (8 threads, barrier-synchronized from a count of 511):
kernel panicked mid-run — serial console (panic.txt):

	Fatal trap 12: page fault while in kernel mode
	current process = 842
	kernel: type 12 trap, code=0
	Stopped at      lockmgr_release+0x11:  movq 0x8(%rdi),%rsi

ssh dropped mid-run (`Connection ... closed by remote host`),
`vm.sh status` ⇒ down — the honest panic signature.

Root cause path: two (or more) threads pass the early unlocked limit check
at `sys_mqueue.c:452` while `p_mqueue_cnt == 511`; the first completes its
open (count 512); the second reaches the under-lock check at :577, takes
the `error = EMFILE; goto exit;` branch — but `mq` is still NULL in this
branch (`mq = mqueue_lookup(name)` returned NULL; `mq = mq_new` happens
only at :583, AFTER the check) — and the shared exit label at :595-596
executes `lockmgr(&mq->mq_mtx, LK_RELEASE)` on a NULL-derived address
(~0x100) → page fault → panic.

Corroboration: the identical crash signature was independently produced when
a rejected first-version DF-2781 fix diff introduced a `goto exit` with
`mq == NULL` at the same site (fixiter1_context.txt) — same trap, same
instruction — confirming the exit-path shape is the hazard and that the
stock :577 check has exactly that shape.

## Fix validation (patched kernel, build #1 04:57)

`fix.diff`: guard the shared release (`if (mq)`) — `mq` is non-NULL on every
other path reaching the label. Patched kernel: the same PoC ran **300
rounds × 8 threads** ("round 299 survived ... survived 300 rounds without
the panic"), guest up (fix_validation.log).

fix_status: **fixed** (fix_baseline_reproduced=1, fix_patched_reproduced=0).
