usched_bsd4.queue_checks accepts <=0 causing NULL-deref/panic in cache-coherent chooseproc
| Field | Value |
|---|---|
| ID | DF-0019 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-20 Improper Input Validation |
| File | sys/kern/usched_bsd4.c |
| Lines | 1483, 1544-1548, 1560, 1572, 2043 |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-06-29 |
| Reported | pending |
Summary
kern.usched_bsd4.queue_checks is registered SYSCTL_ADD_INT(..., CTLFLAG_RW,
...) with the default sysctl_handle_int handler (no lower bound). Setting it
to 0 (or negative) โ a root operation โ makes
bsd4_chooseproc_locked_cache_coherent()'s while (checks <
usched_bsd4_queue_checks) loop never execute, leaving min_level_lwp == NULL.
The function then assigns lp = min_level_lwp (NULL) and trips
KASSERT(lp) (INVARIANTS) or NULL-dereferences lp (production), panicking
the kernel on the next user reschedule in cache_coherent mode with a
non-empty runqueue.
Root cause
while (checks < usched_bsd4_queue_checks) { /* body never runs if <= 0 */
...
}
...
lp = min_level_lwp; /* :1544 NULL */
q = min_q; which = min_which; pri = min_pri;
KASSERT(lp, ("chooseproc: at least the first lp was good")); /* :1548 */
...
if (chklp) {
if (chklp->lwp_priority < lp->lwp_priority + PPQ) { ... } /* :1560 NULL deref */
}
...
TAILQ_REMOVE(q, lp, lwp_procq); /* :1572 NULL deref */
min_level_lwp is initialized NULL (~:1428) and is only assigned inside
the loop body, which the loop guard (checks < queue_checks, with checks
starting at 0) never enters when usched_bsd4_queue_checks <= 0. The sysctl
registration (:~2043) uses SYSCTL_ADD_INT(..., CTLFLAG_RW,
&usched_bsd4_queue_checks, 5, ...) with no handler-level bound โ contrast
sysctl_usched_bsd4_stick_to_level (:1868-1882) which validates its range,
and bsd4_recalculate_estcpu which clamps usched_bsd4_decay to [1..1024]
(:1071-1075). queue_checks has neither protection.
Threat model & preconditions
- Attacker position: privileged โ writing
kern.usched_bsd4.*requiresSYSCAP_NOSYSCTL_WR(root). So this is a privileged-user-triggered kernel panic (self-DoS / hardening defect), not a privilege escalation. - Privileges gained or impact: kernel panic (full-system DoS). No integrity/confidentiality impact.
- Required config or capabilities: root; the
bsd4scheduler in use;kern.usched_bsd4.cache_coherent != 0(boot default on multi-node/HT hardware) and a non-empty runqueue. - Reachability:
sysctl kern.usched_bsd4.queue_checks=0, then any context switch that reachesbsd4_chooseproc_locked_cache_coherent.
Proof of concept
PoC source: findings/poc/DF-0019/queue_checks_panic.sh
Run (root, disposable VM)
sh findings/poc/DF-0019/queue_checks_panic.sh
Expected output
panic: chooseproc: at least the first lp was good # INVARIANTS kernel (or) Fatal trap 12 ... in bsd4_chooseproc_locked_cache_coherent # production
Impact
Root-only self-DoS. The kernel should not panic from a sysctl write of an in-range integer โ it is a robustness/hardening defect and a violation of the scheduler's own invariants. Rated Low (privileged trigger).
Recommended fix
Validate the sysctl with a custom handler (reject < 1), mirroring
stick_to_level, and/or clamp in the consumer:
--- a/sys/kern/usched_bsd4.c
+++ b/sys/kern/usched_bsd4.c
@@ -1480,7 +1480,7 @@
* minimize the contention (we are in a locked region
*/
- while (checks < usched_bsd4_queue_checks) {
+ while (checks < (usched_bsd4_queue_checks > 0 ? usched_bsd4_queue_checks : 1)) {
plus a sysctl_usched_bsd4_queue_checks handler that returns EINVAL for
new_val < 1 (registered via SYSCTL_ADD_PROC), matching the
sysctl_usched_bsd4_stick_to_level pattern at :1868-1882.
References
sys/kern/usched_bsd4.c:1483โ unchecked loop bound.sys/kern/usched_bsd4.c:1544-1572โ NULLlpKASSERT / derefs.sys/kern/usched_bsd4.c:2043โSYSCTL_ADD_INTregistration (no bound).sys/kern/usched_bsd4.c:1868โstick_to_level(validation pattern to mirror).- CWE-20 Improper Input Validation.
Timeline
- 2026-06-29 Discovered during automated file-by-file audit of
sys/kern/usched_bsd4.c. - pending Reported to DragonFlyBSD security contact.