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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4719 Β· 4 files
FileTypeDescriptionSize
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_testable
↓ fix.diffper-fix-DF-4719

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