_gtaskqueue_start_threads() reports total thread-creation failure as success; queue teardown lifecycle is stubbed, so a half-born queue silently hangs all future drainers
| Field | Value |
|---|---|
| ID | DF-2850 |
| 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:L |
| CWE | CWE-755 Improper Handling of Exceptional Conditions |
| File | sys/kern/subr_gtaskqueue.c |
| Lines | 455-471 (dead teardown :147-160/:801-804) |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
If lwkt_create() fails, _gtaskqueue_start_threads() NULLs the slot,
skips tq_tcount++ and still returns 0 unconditionally β the comment's
promised cleanup points at gtaskqueue_free(), which is static
__unused dead code, and taskqgroup_destroy() is an empty stub. A
queue whose threads failed to start still accepts enqueues and wakes
nobody; its tasks never run; any drain on it sleeps forever (timo=0)
with no error. Silent permanent kernel-thread hang under thread-table/
kmem exhaustion at queue-start time. No deterministic guest PoC
(code-path analysis; findings/poc/DF-2850/NOTES.md).
Recommended fix
Track successful creates, tear down partial state and return the error; make TASKQGROUP_DEFINE's SYSINIT treat a failed queue as fatal at boot; implement or delete the dead destroy/free declarations.
Timeline
- 2026-09-02 Discovered during pass-2 audit of subr_gtaskqueue.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2850 Β· 1 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | β | 1.3 KB | view raw |
Fix verification
not_testableError propagation + partial teardown fix compile-validated; lwkt_create failure not injectable for A/B.
compile-validated in the fix-all kernel build (make nativekernel, 0 errors)
Confirmed kernel references
Detail
Evidence (decisive lines)
subr_gtaskqueue.c:455-461 swallow + :471 return 0; :147 static __unused gtaskqueue_free; :801-804 empty taskqgroup_destroy
PoC changes
n/a
Verified recommended fix
--- sys/kern/subr_gtaskqueue.c 2026-06-29 12:51:19.000000000 +0000
Verdict
Code-verified failure-swallowing; the failure cannot be injected on a live guest. _gtaskqueue_start_threads (sys/kern/subr_gtaskqueue.c:442-471) NULLs the thread slot and continues on lwkt_create error, then unconditionally returns 0 (:471) - total failure yields a thread-less queue whose enqueues succeed, tasks never run, and every drain sleeps forever (timo=0). The promised cleanup is dead code: gtaskqueue_free is static void __unused (:147-148) and taskqgroup_destroy is an empty stub (:801-804). Injecting the failure requires making lwkt_create fail (thread-structure exhaustion at exactly queue-start time) - not producible deterministically on this guest, and no sysctl pins the thread limit. The consequence (a never-started queue hangs all drainers) is structural and code-certain; the fix (track first error, tear down partial state, return it) is compile-validated.
No comments yet.