# DF-2777 VERDICT — reproduced (three distinct panics; fix validated)

## Bottom line

`register_int` publishes `i_state = ISTATE_NORMAL` (kern_intr.c:326) before
it allocates/creates `i_thread` (:327-331) — a window that spans a blocking
`M_INTWAIT` kmalloc and `lwkt_create` — and its emergency-thread block
(:308-319) is a check-then-create spanning `lwkt_create` +
`systimer_init_periodic_nq`. With dormant hook points compiled into
kern_intr.c that stall the first registrant inside these windows (a stand-in
for the blocking allocations starving under memory pressure, or any
preemption), all three predicted failure modes reproduced exactly on the
stock INVARIANTS guest:

- **SC1** (`panic_sc1.txt`): second concurrent `register_int(254,
  INTR_MPSAFE|INTR_CLOCK, cpu2)` observed `ISTATE_NORMAL` with NULL
  `i_thread` and executed `atomic_set_int(&info->i_thread->td_flags,
  TDF_CLKTHREAD)` (kern_intr.c:349):
  `Stopped at register_int+0x1b9: lock orl $0x20000000,0xd8(%rdx)`
  (write fault at 0xd8 = offsetof(struct thread, td_flags)).
- **SC2** (`panic_sc2.txt`): with the first registrant stalled mid-window
  and the second's rec already linked, an interrupt arrival
  (`sched_ithd_soft(255)`) dereferenced `info->i_thread->td_gd`
  (kern_intr.c:589):
  `Stopped at sched_ithd_intern+0x1f: movq 0xb8(%rdx),%r8`
  (read fault at 0xb8 = offsetof(struct thread, td_gd)).
- **SC3** (`panic_sc3.txt`): two concurrent first-registrations on cpu2
  (the boot-time window reopened by the rig-only `dfh_reset_emergency`,
  because a booted system has already created every CPU's emergency thread)
  both entered the emergency block; the second
  `systimer_init_periodic_nq(&emergency_intr_timer[2], ...)` re-initialized
  an already-armed timer and crashed inside `systimer_add`
  (kern_systimer.c): `Stopped at systimer_add+0x15c: movq (%rcx),%rsi`
  (VA 0, thread CRIT). The stock `KKASSERT((info->flags & SYSTF_ONQUEUE)
  == 0)` at kern_systimer.c:148 does not save the code because the re-init
  wipes `flags` before arming again — the timer subsystem then runs on
  corrupted state.

## Threat model honesty

Reaching the windows requires two concurrent `register_int` calls for the
same (cpu, intr) — i.e. driver probe/attach races or boot-time
first-registration concurrency — or an interrupt arriving during the window
of a first registration. All are kernel-internal; an unprivileged user
cannot drive `register_int` directly. Impact = kernel panic (DoS at
driver-attach time); no memory disclosure or corruption control was
demonstrated beyond the crash. Severity Low as filed is right. The SC3
window on a booted system is closed in practice (first boot-time
registration wins permanently); the rig reopens it to expose the defect —
labeled as such.

## Fix validation

`fix.diff` (DF-2777 hunks), applied to a pristine tree, hooks preserved:

- ithread creation claimed by `atomic_cmpset_int(&info->i_state,
  ISTATE_NOTHREAD, ISTATE_CREATING)`, thread built into a local,
  `info->i_thread` published BEFORE `i_state = ISTATE_NORMAL`;
- `if (intr_flags & INTR_CLOCK)` NULL-guards `info->i_thread` (the creator
  sets the flag itself after publishing);
- `sched_ithd_intern` treats `i_thread == NULL` as a rate-limited stray;
- emergency block gated by a once-only cmpset.

On the rebuilt fixed kernel (build.fixed.log.gz) the exact same scenarios
all survive with the same orchestration:
`DF2777-SC1: r1=0xfffff8008daa43e0 r2=0xfffff8008daa43a8 -- survived, no
NULL-deref`; `sched_ithd: stray interrupt 255 on cpu3` + `SC2 ... survived`;
`DF2777-SC3: ... survived, no double-arm` (df2777_fixed.dmesg).

## Kernel references

- sys/kern/kern_intr.c:308-319 (emergency check-then-create)
- sys/kern/kern_intr.c:325-337 (state published before i_thread, blocking window)
- sys/kern/kern_intr.c:348-350 (TDF_CLKTHREAD deref of possibly-NULL i_thread)
- sys/kern/kern_intr.c:582-602 (sched_ithd_intern i_thread->td_gd deref)
- sys/kern/kern_systimer.c:144-148 (systimer_add / SYSTF_ONQUEUE assert)

## Rig honesty notes

- Hooks are pure no-ops unless a scenario arms them (single flag test);
  boot-time and driver registration paths were unaffected in 3 booted
  harness kernels.
- The stalls substitute for real blocking/preemption inside the windows
  (M_INTWAIT kmalloc under memory pressure, scheduler preemption); they do
  not create windows that do not exist in the stock code — the hooked
  lines are exactly the window boundaries the finding cites.

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