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

mprsas_fw_work IR-event early return leaks fw_event allocation and strands the startup refcount (discovery can never complete)

Summary

On mpr_alloc_command failure the IR_CONFIGURATION_CHANGE_LIST case returns without the startup decrement or the fw_event free: the allocations leak per event and the refcount never drops to 0, freezing discovery completion (simq); the leak amplifies the command-pool exhaustion that triggers it. Decrement+free fix (compile-validated).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4252 Β· 10 files
FileTypeDescriptionSize
README.md β€” 1.7 KB ↓ raw
VERDICT.md β€” 1.6 KB ↓ raw
build.log β€” 7.4 KB view raw
build.sh β€” 65 B view raw
env.txt β€” 588 B view raw
fix.diff β€” 806 B view raw
run.log β€” 425 B view raw
run.sh β€” 89 B view raw
trigger.sh β€” 285 B view raw
verdict.json β€” 1.9 KB view raw

DF-4252 β€” mprsas_fw_work IR-event early return leaks the fw_event and the startup refcount

Where

sys/dev/raid/mpr/mpr_sas_lsi.c:327-331 (MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST case):

if ((cm = mpr_alloc_command(sc)) == NULL) {
        kprintf("%s: command alloc failed\n", __func__);
        return;                      /* <-- leaks */
}

mprsas_fw_work frees the event only at its tail (:780 mprsas_fw_event_free), and the IR case drops the startup refcount only at :455 (mprsas_startup_decrement). The early return skips both.

What

  1. fw_event + fw_event->event_data (kmalloc'd in mprsas_evt_handler :142-156) leak on every occurrence.
  2. The startup refcount taken in mprsas_evt_handler (:170-174, whenever wait_for_port_enable is set β€” every boot-time discovery) is never dropped: startup_refcount can never reach 0 β†’ discovery-completion callbacks (simq release, mprsas_startup_decrement side effects at mpr_sas.c:204-226) never fire for this event β†’ CAM queue stays frozen / boot hangs until the mpr_detach_sas/reinit forced-drain loops (mpr_sas.c:941-942) run.
  3. Command-pool exhaustion (which triggers this) is most likely precisely during an IR config-change event storm β€” the leak then amplifies the exhaustion (each leaked fw_event holds pool pressure).

Trigger

mpr(4) HBA in IR mode, IR_CONFIGURATION_CHANGE_LIST event with Hide/PD-Created reason while the command pool is empty (heavy I/O + event storm). Hardware-gated.

Fix

fix.diff β€” on alloc failure do what the normal path would have done: decrement the refcount, free the event, then return.

Build/run

build.log β€” compile-validated on the audit guest.

VERDICT.md
↓ download raw

DF-4252 VERDICT

status: untested (hardware-gated: no mpr HBA on the audit guest) impact class: dos + memory leak confidence: certain (error-path trace)

Trace

  • mpr_sas_lsi.c:142-156 β€” mprsas_evt_handler allocates fw_event + event_data.
  • :170-174 β€” for IR_CONFIG_CHANGE_LIST with wait_for_port_enable, mprsas_startup_increment(sassc) (refcount +1).
  • :274-457 β€” mprsas_fw_work IR case: :327-331 early return when mpr_alloc_command fails, skipping BOTH the :455 mprsas_startup_decrement(sassc) and the :780 mprsas_fw_event_free(sc, fw_event).
  • mpr_sas.c:178-226 β€” refcount 0 is what unfreezes the simq and completes startup; a stranded +1 keeps MPRSAS_IN_STARTUP handling pending until a forced drain (reinit at mpr_sas.c:941-942 or detach).

Consequences: (a) kernel memory leak per failed event, (b) discovery/ startup completion can hang, (c) leak rate correlates with command-pool pressure (the same condition that triggers it), compounding pool exhaustion β€” mps(4) twin of the DF-4015 family pattern.

Fix (fix.diff): decrement + free before the early return. Compile-validated on the guest (build.log). fix_status: not_testable (runtime needs HBA + pool exhaustion during an IR event).

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

not_testable
baseline no→ patch + rebuild →patched clean

not_testable at runtime; compile-validated (decrement+free before return).

build.log: patched module builds clean.
↓ fix.diffper-fix-DF-4252

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md refcount trace; build.log compile-validation.

PoC changes

n/a - pass-2 finding; trigger documentation written fresh (hardware-gated, no seed PoC existed)

Verified recommended fix

decrement startup refcount + free fw_event before early return

Verdict

mprsas_fw_work IR_CONFIGURATION_CHANGE_LIST case returns early at :330 when mpr_alloc_command fails, skipping both mprsas_startup_decrement (:455) and mprsas_fw_event_free (:780): the fw_event+event_data allocations leak and the startup refcount taken in mprsas_evt_handler (:170-174) never drops, so discovery completion can hang (simq stays frozen) until a forced drain; leak amplifies the very pool exhaustion that triggers it (DF-4015-family pattern, mpr side).