sili OS-glue lock lifecycle asymmetry: three of four per-port locks are never uninited, and the port-alloc error unwinds lockuninit() a never-lockinit'ed ap_lock
Summary
Only ap_lock is uninited of the four lockinit'ed locks; the port-alloc error unwind lockuninits ap_lock on a never-init lock (survives only via M_ZERO's lk_count==0 satisfying the KKASSERT). E3 of the DF-5044 harness ran the stock kernel's own stop_port on the exact error-unwind shape - returned without panic. Defense-in-depth; complete-uninit fix validated.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5045 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| run.log | run-log | E1/E2/E3 run; E3 lines show the never-init lockuninit executing and returning | 1.8 KB | view raw |
| fix.diff | suggested-fix | lockuninit symmetry hunks (same diff as DF-5044) | 3.8 KB | view raw |
| VERDICT.md | verdict | full narrative | 2.4 KB | β raw |
| ../DF-5044/ | harness | shared trigger module (trigger.c/Makefile/build.sh) + fix kernel build log | 4.0 KB | β download |
DF-5045 β VERDICT
Verdict: REPRODUCED (runtime execution of the asymmetric path; Info-grade hardening finding β no security impact demonstrated) Class: lock lifecycle asymmetry (CWE-667) Impact ceiling: none (defense-in-depth; the defect classes it guards against β lockuninit on held/recycled locks β are not reachable as shipped) Confidence: certain
Reproduction
E3 of the DF-5044 harness on the baseline kernel (run.log): the stock
kernel's own sili_os_stop_port() was called on the exact state the
sili_port_alloc() error unwinds produce (ap_sc set at sili.c:165,
ap_thread == NULL, zeroed locks) and executed lockuninit(&ap->ap_lock)
on the never-lockinit'ed lock, returning without panic β benign only
because M_ZERO guarantees lk_count == 0, which is what satisfies
lockuninit()'s KKASSERT (sys/kern/kern_lock.c:1330-1335). On the
fix-patched kernel the same call also returns 0 (regression check in the
DF-5044 pack's run.4.log).
Mechanism (source-confirmed)
- init:
lockinit(&ap->ap_lock),lockinit(&ap->ap_sim_lock),lockinit(&ap->ap_sig_lock)(sili_dragonfly.c:198-200) +lockinit(&ap->ap_ccb_lock)(sili.c:170) - uninit:
lockuninit(&ap->ap_lock)only (sili_dragonfly.c:223) β and this also runs on ports whose start_port never executed (the freeport error paths withap_scset). ap_sim_lockis additionally handed to CAM as the sim lock (sili_cam.c) and outlives the sim; none of the three extra locks are ever uninited.
Fix
fix.diff (same file as DF-5044's; the lockuninit-symmetry hunks):
lockuninit(&ap->ap_sim_lock); lockuninit(&ap->ap_sig_lock); in
sili_os_stop_port(), and lockuninit(&ap->ap_ccb_lock) in
sili_port_free() before kfree(ap). Validated by the DF-5044 fix kernel
build (-Werror, rc=0) and the patched-kernel E3 regression run.
Gating precondition
None for observing the asymmetry (kld, stock kernel, no hardware); the guarded-against hazards themselves are not reachable as shipped.
Exploit chain
Not applicable.
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.
Fix verification
fixedThe symmetry hunks are part of the DF-5044 fix kernel (quickkernel -Werror, rc=0, fix_build.log). On the patched kernel the E3 call still returns cleanly (run.4.log in the DF-5044 pack) and now also uninits ap_sim_lock/ap_sig_lock; ap_ccb_lock is uninited by the sili_port_free hunk. As an Info finding with no observable failure mode on baseline, the A/B shows path equivalence plus the restored contract.
DF-5044/fix_build.log (kernel build with the shared fix.diff, rc=0); DF-5044/run.4.log (E3 on patched kernel returns); run.log (E3 on baseline kernel)
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log last lines ('DF5045: E3: calling sili_os_stop_port() on a port whose ap_lock was NEVER lockinit'ed ... E3: returned - lockuninit(&ap->ap_lock) executed on the uninitialized zeroed lock'); DF-5044 pack run.4.log (E3 returns on the fix-patched kernel); DF-5044 fix_build.log (kernel build rc=0); fix.diff (symmetry hunks); VERDICT.md
PoC changes
E3 of the self-authored DF-5044 harness (no seeded PoC): zeroed struct sili_port with ap_sc set and ap_thread NULL - the exact sili_port_alloc error-unwind shape - passed to the stock kernel's sili_os_stop_port().
Verified recommended fix
lockuninit(&ap->ap_sim_lock) and lockuninit(&ap->ap_sig_lock) in sili_os_stop_port(), and lockuninit(&ap->ap_ccb_lock) in sili_port_free() before kfree(ap) - see fix.diff (same as DF-5044)
Verdict
sili OS-glue lock lifecycle asymmetry: sili_os_start_port() lockinits ap_lock/ap_sim_lock/ap_sig_lock (sili_dragonfly.c:198-200) and sili_port_alloc() adds ap_ccb_lock (sili.c:170), but sili_os_stop_port() uninits ONLY ap_lock (sili_dragonfly.c:223) - the other three are never uninited on any path; conversely the sili_port_alloc error unwinds (sili.c:186/221 goto freeport with ap_sc set at :165, thread never started) execute lockuninit(&ap->ap_lock) on a lock that was never lockinit'ed, passing lockuninit()'s KKASSERT (kern_lock.c:1330) only because the M_ZERO kmalloc leaves lk_count==0. The never-init lockuninit path was executed at runtime on the stock kernel (E3 of the DF-5044 harness: zeroed port with ap_sc set and ap_thread NULL handed to the kernel's own sili_os_stop_port - returned without panic, proving the contract violation executes benignly today). Info-grade hardening: no security impact demonstrated; the fix restores symmetry and is compile- and runtime-validated with the DF-5044 fix kernel (quickkernel -Werror rc=0; E3 still returns 0 on the patched kernel).
No comments yet.