β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5045

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5045 Β· 4 files
FileTypeDescriptionSize
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
VERDICT.md verdict full narrative
↓ download raw

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 with ap_sc set).
  • ap_sim_lock is 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

fixed
baseline reproduced→ patch + rebuild →patched clean

The 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)
↓ fix.diffper-fix-DF-5045

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).