register_int check-then-create windows span blocking allocations: NULL info->i_thread dereference and re-arm of an already-armed emergency systimer under concurrent registration
| Field | Value |
|---|---|
| ID | DF-2777 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-362 / CWE-476 |
| File | sys/kern/kern_intr.c |
| Lines | 308-319, 325-337 (use :349, :585-596) |
| Area | kern |
| Confidence | speculative |
| Discovered | 2026-08-31 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
register_int sets i_state = ISTATE_NORMAL before the potentially blocking kmalloc(M_INTWAIT)/lwkt_create. If the creating thread blocks, a second registration on the same target CPU observes ISTATE_NORMAL and proceeds to use info->i_thread (still NULL) → atomic_set_int on td_flags through NULL + sched_ithd_intern dereference → NULL-deref panic. Symmetrically, the emergency-thread creation checks emergency_intr_thread[cpuid]==NULL then runs blocking calls; two interleaved registrations both pass and the second systimer_init_periodic re-adds the ALREADY-ARMED timer (systimer_add KKASSERTs !SYSTF_ONQUEUE on INVARIANTS; production: the same node linked twice into gd_systimerq, corrupting the per-CPU timer queue). Concurrent driver attach (parallel probe/attach, kldload racing boot attach) on the same CPU plus memory pressure; not unpriv-reachable.
Recommended fix
Publish i_thread fully before setting ISTATE_NORMAL; create the emergency thread under a once-only guard that cannot be re-entered across a blocking call (set the slot pointer only after systimer init; check under crit_enter before re-arming).
Timeline
- 2026-08-31 Discovered during pass-2 audit of kern_intr.c (GLM 5.3).
No comments yet.