Pending AAC_EVENT_CMFREE fires after aac_cam_detach freed the sim -> xpt_release_simq/xpt_done through freed objects (UAF)
Summary
The ENOMEM path queues a CMFREE event holding the ccb (invisible to CAM, never queued); detach frees the sim without draining the event queue - a pending event after detach fires against freed sim/softc. Root-triggered detach during FIB exhaustion; speculative (hw-gated). Drain/cancel fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4719 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.5 KB | β raw | |
| fix.diff | β | 806 B | view raw | |
| verdict.json | β | 1.6 KB | view raw | |
| manifest.json | β | 505 B | view raw |
DF-4719 β aac_cam: pending AAC_EVENT_CMFREE fires after aac_cam_detach freed the sim β xpt_release_simq/xpt_done on freed objects
Root cause (code trace; hw-gated β no AAC adapter in the QEMU guest)
When aac_alloc_command() fails, aac_cam_action() freezes the simq and
queues an AAC_EVENT_CMFREE holding the ccb (with sim_priv[0].ptr =
camsc) (sys/dev/raid/aac/aac_cam.c:395-407). The event fires from
aac_release_command() (sys/dev/raid/aac/aac.c:1416-1420) whenever a
command returns to the pool, and aac_cam_event() then calls
xpt_release_simq(camsc->sim, 1) and xpt_done(ccb)
(aac_cam.c:165-172).
aac_cam_detach() (:191-213) frees camsc->sim via cam_sim_free()
without cancelling pending CMFREE events (the frozen ccb is not queued in
CAM at all β CAM cannot see it). If the adapter is detached while a CMFREE
event is pending (FIB pool exhausted + device detach), the next command
release fires the event and dereferences the freed sim (and freed
camsc softc) β use-after-free write inside CAM.
Reachability: root-initiated detach (or driver shutdown) while the FIB pool is exhausted and a ccb waits on the event queue β narrow, but the leak of the pending event is structural (nothing ever removes it). Speculative/likely by trace; not runtime-verified (no AAC hardware).
Fix
Cancel the pending events for this sim in aac_cam_detach() before
freeing it β fix.diff (completes the stranded ccbs with
CAM_REQ_ABORTED after releasing the simq).
Fix verification
not_testableConfirmed kernel references
Detail
Exploit chain
FIB pool exhausted (e.g. hung firmware under I/O) -> ccb frozen on CMFREE event -> device detach frees sim -> next command release fires event -> xpt_release_simq on freed sim (UAF write in CAM)
Evidence (decisive lines)
code trace: aac_cam.c:395-407 (event queued with ccb), aac_cam.c:165-172 (event uses camsc->sim), aac_cam.c:191-213 (detach frees sim, never drains aac_ev_cmfree)
PoC changes
n/a
Verified recommended fix
drain/cancel CMFREE events referencing the sim in aac_cam_detach before cam_sim_free (fix.diff)
Verdict
aac_cam_detach() frees camsc->sim without cancelling AAC_EVENT_CMFREE events queued by aac_cam_action()'s ENOMEM path (aac_cam.c:395-407); aac_cam_event() (aac_cam.c:165-172) later calls xpt_release_simq/xpt_done through the freed sim/softc -> UAF. Requires adapter detach while a ccb waits on the exhausted FIB pool; structural leak of the event is clear from the trace, the exact interleaving is speculative. hw-gated (no AAC emulation) - not runtime-verified. fix.diff cancels pending events at detach.
No comments yet.