DF-4558 / verdict.json
{ "finding_id": "DF-4558", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Not executed: the audit guest compiles natapicam into X86_64_GENERIC (sys/config/X86_64_GENERIC:82; kldstat shows no atapicam.ko) so the MOD_UNLOAD module-event path (atapi-cam.c:916-930) cannot run there and kldunload atapicam is not possible. The defect itself is established by source trace (VERDICT.md): device_delete_child()s return is ignored and kfree(scp, M_ATACAM) runs unconditionally at :927 even when free_softc() left BUS_REGISTERED set and the cam_sim deliberately alive (:894-903) - the still-registered SIM keeps a dangling softc, and the next CCB on that bus runs atapi_action on freed memory including lockmgr on a freed, lockuninitd state_lock (:482) - a UAF write. Additionally device_delete_child() failure itself (detach refused) also precedes the unconditional kfree. Real but privileged-only (kldunload=root); any system running the loadable atapicam.ko module is exposed.", "exploit_chain": "kldunload atapicam (root) with a live CAM peripheral on the bus -> xpt_bus_deregister fails -> SIM kept registered, BUS_REGISTERED stays set -> lockuninit(state_lock) -> handler kfree(scp) -> sim->softc dangles -> any cd0 I/O/rescan -> atapi_action reads/writes freed softc (lockmgr UAF write). Escalation not applicable: trigger requires root.", "evidence": "VERDICT.md (full trace with path:line); README.md; fix.diff (git apply --check OK, scoped to the unload handler)", "kernel_refs": [ "sys/dev/disk/nata/atapi-cam.c:916", "sys/dev/disk/nata/atapi-cam.c:925", "sys/dev/disk/nata/atapi-cam.c:927", "sys/dev/disk/nata/atapi-cam.c:894", "sys/dev/disk/nata/atapi-cam.c:900", "sys/dev/disk/nata/atapi-cam.c:906", "sys/dev/disk/nata/atapi-cam.c:482", "sys/kern/subr_bus.c:1788" ], "poc_changes": "n/a - no PoC executed; run.sh documents the hypothetical trigger for modular systems", "attempts": 0, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 0, "guest_dirty": 0, "build_cmd": "none (trigger is kldunload on a modular atapicam system)", "run_cmd": "kldunload atapicam (not possible on this guest: driver compiled-in)", "code_hash": "", "fix_status": "not_tested", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored (guard: only free the external softc when BUS_REGISTERED was cleared and device_delete_child succeeded; return EBUSY to abort the unload otherwise). Not kernel-built: the path cannot be exercised on this guest (driver compiled-in); logic-compiles by inspection (uses only existing symbols).", "fix_evidence": "findings/poc/DF-4558/fix.diff", "recommended_fix": "Free the softc only when the SIM was actually deregistered/freed; honor device_delete_child() failure and abort the unload with EBUSY instead of leaving a dangling cam_sim->softc", "notes": "Guest untouched for this finding (no build/boot performed for it); guest left clean on with-src snapshot after DF-4557 validation. Distinct from DF-2500 (pending hcbs outliving detach): here the softc itself is freed while the SIM remains registered." } |