DragonFlyBSD Kernel Audit
DF-2915 / fix.diff
← back to finding ↓ download raw
DF-2915 fix: sleepq_lock() assumed objcache_get() returns zeroed
sleepqueue_wchan objects.  sleepq_wc_cache is an objcache_create_simple()
cache: its allocator objcache_malloc_alloc() (kern_objcache.c:571-577)
kmalloc()s WITHOUT M_ZERO and no ctor is registered
(kern_objcache.c:386-389), so freshly allocated wc's contain garbage.
The KKASSERT at the old line fires (panics INVARIANTS kernels) or the
garbage object enters sc_wchead and permanently breaks the free-slot
invariant (production kernels: stuck entries, inflated sc_free_count,
unbounded re-allocation loop).

Explicitly zero the object after objcache_get().  Recycled objects were
already reset by the release paths, so this only fixes the fresh-alloc
case and is otherwise a no-op.

--- a/sys/kern/subr_sleepqueue.c
+++ b/sys/kern/subr_sleepqueue.c
@@ -206,7 +206,13 @@
 		 */
 		spin_unlock(&sc->sc_spin);
 		wc = objcache_get(sleepq_wc_cache, M_WAITOK);
-		KKASSERT(wc->wc_wchan == NULL && wc->wc_refs == 0);
+		/*
+		 * DF-2915: objcache_create_simple() applies no zeroing
+		 * (objcache_malloc_alloc, kern_objcache.c) and we register
+		 * no ctor, so a freshly kmalloc'd wc contains garbage.
+		 * Initialize it explicitly.
+		 */
+		bzero(wc, sizeof(*wc));
 		wc->wc_sc = sc;
 		spin_lock(&sc->sc_spin);
 		TAILQ_INSERT_TAIL(&sc->sc_wchead, wc, wc_entry);