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

sc->map_update_cmd is never cleared: shutdown aborts a recycled pooled mfi command (stale handle β†’ wrong-command abort)

Summary

sc->map_update_cmd is assigned exactly once and cleared nowhere in the driver. All three release paths for the map-sync mfi command return it to the shared 32-entry pool without nulling the pointer. mrsas_shutdown_ctlr then issues the abort on the recycled slot, and the abort frame is built from the command's current index/frame_phys_addr, so the firmware aborts whatever unrelated in-flight ioctl passthrough or internal DCMD now occupies it - its waiter receives a spurious abort completion. Shutdown-time cross-command abort of an unrelated management/ioctl command (wrong status delivered to a bystander). Indices stay in-bounds and pooled objects are permanent allocations, so impact is logic confusion, not wild memory access. Clear-handle-at-every-release fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3846 Β· 7 files
FileTypeDescriptionSize
README.md β€” 1.2 KB ↓ raw
VERDICT.md β€” 3.2 KB ↓ raw
run.log β€” 90 B view raw
env.txt β€” 260 B view raw
fix.diff β€” 1.8 KB view raw
manifest.json β€” 777 B view raw
verdict.json β€” 2.8 KB view raw

DF-3846 β€” sc->map_update_cmd never cleared: dangling pooled command aborted at shutdown

sc->map_update_cmd is set only in mrsas_sync_map_info() (mrsas.c:3239) and cleared nowhere. The map-sync mfi command is released to the shared pool at mrsas.c:2953 (NOT_FOUND failure β€” no follow-up sync), mrsas.c:2960 (normal completion), and mrsas.c:2454 (OCR re-fire loop), always leaving the pointer dangling. mrsas_shutdown_ctlr() (mrsas.c:3041-3042) then issues mrsas_issue_blocked_abort_cmd() on the recycled slot β†’ the firmware aborts whatever command now occupies that index/frame (an unrelated in-flight ioctl or internal DCMD) β†’ spurious abort completion for a bystander command at shutdown.

Impact: wrong-command abort / status confusion; indices in-bounds; no wild write. Low severity, hardware-gated.

Reproduce

Needs an attached MegaRAID HBA that completes (or NOT_FOUND-fails) a map sync plus a later shutdown after the 32-entry mfi pool recycled the slot. Guest has mrsas compiled in but no LSI device / /dev/mrsas* (run.log) β€” path unreachable in the VM.

Files

  • VERDICT.md, run.log, env.txt, fix.diff, manifest.json, verdict.json
VERDICT.md
↓ download raw

VERDICT β€” DF-3846 (sc->map_update_cmd never cleared: dangling pooled command aborted at shutdown)

status: inconclusive (hardware-gated; dangling-pointer structure source-certain) confidence: certain (lifetime defect at source level) Β· class: stale-handle / cross-command abort (logic confusion; in-bounds indices)

The defect (source)

sc->map_update_cmd is assigned once β€” mrsas_sync_map_info(), mrsas.c:3239 β€” and cleared nowhere (grep across mrsas*.c: only writers are 3239; only reader is mrsas_shutdown_ctlr, mrsas.c:3041-3042).

Every completion path for a RAID-map sync command returns the mfi command to the free pool without touching sc->map_update_cmd:

  • mrsas_complete_mptmfi_passthru() map branch, success/normal: mrsas_release_mfi_cmd(cmd) at mrsas.c:2960 (and the map_id++ path re-issues a new sync which re-points it at 3239 β€” but only when a new sync actually fires);
  • map-sync failed MFI_STAT_NOT_FOUND: mrsas_release_mfi_cmd(cmd) at mrsas.c:2953 then break β€” no new sync is issued, so sc->map_update_cmd is left dangling to a command that is now on the free list;
  • mrsas_reset_ctrl() re-fire loop: for MR_DCMD_LD_MAP_GET_INFO opcodes it does mrsas_release_mfi_cmd(mfi_cmd); mrsas_release_mpt_cmd(mpt_cmd); at mrsas.c:2454-2455 β€” again leaving sc->map_update_cmd pointing at the released command.

Consequence

At detach/shutdown, mrsas_shutdown_ctlr() (mrsas.c:3038-3042) does:

if (sc->map_update_cmd)
    mrsas_issue_blocked_abort_cmd(sc, sc->map_update_cmd);

mrsas_issue_blocked_abort_cmd (mrsas.c:3465-3517) builds the abort frame from cmd_to_abort->index and cmd_to_abort->frame_phys_addr (mrsas.c:3486-3488). If the pooled command has been recycled in the meantime (its 32-entry pool is shared by all internal and ioctl passthrough traffic), the firmware is asked to abort whatever command now occupies that index/frame β€” an in-flight ioctl passthrough of another thread or an internal DCMD. That command's waiter receives a spurious abort completion (mrsas_complete_abort / mrsas_wakeup), i.e. an unrelated management command fails at shutdown time. All indices remain in-bounds; the pooled objects are permanent allocations, so this is a stale-handle logic defect (wrong-command abort / status confusion), not a wild memory access β€” hence Low severity.

Why not reproduced on the guest

Requires an attached MegaRAID controller that completes (or fails with NOT_FOUND) a map sync and then a shutdown during which the command slot was recycled. The guest has mrsas compiled in but no LSI device (run.log). Source structure is certain: there is no clearing store to sc->map_update_cmd anywhere in the driver.

Fix

fix.diff: null the pointer at all three release sites and re-check the command is still the registered map-sync command before aborting at shutdown.

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

fix.diff nulls the pointer at all three release sites; obviously removes the dangling consumer at mrsas.c:3041. Not boot-testable without the HBA -> not_testable.

fix.diff four hunks at the exact release/consumer lines.
↓ fix.diffper-fix-DF-3846

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md with the three uncleared release sites and the shutdown consumer; grep over mrsas*.c shows sc->map_update_cmd written only at mrsas.c:3239 and read only at mrsas.c:3041-3042.

PoC changes

No seed PoC; trigger requires an attached HBA completing a map sync and a later shutdown after pool recycling. Guest cannot reach the path.

Verified recommended fix

Clear sc->map_update_cmd whenever the map-sync mfi command is released (mrsas.c:2953, 2960, 2454) so shutdown can never abort a recycled command.

Verdict

Stale-handle lifetime defect: sc->map_update_cmd is assigned once in mrsas_sync_map_info (mrsas.c:3239) and never cleared anywhere in the driver. All three release paths for the map-sync mfi command return it to the shared 32-entry pool without nulling the pointer: the NOT_FOUND failure path (mrsas.c:2953, which issues no follow-up sync), the normal completion path (mrsas.c:2960), and the OCR re-fire loop (mrsas.c:2454-2455). mrsas_shutdown_ctlr (mrsas.c:3041-3042) later aborts whatever command now occupies that index/frame β€” after recycling this is an unrelated in-flight ioctl passthrough or internal DCMD of another thread, which receives a spurious abort completion. All indices stay in-bounds and pooled objects are permanent, so impact is wrong-command abort / status confusion at shutdown, not wild memory access (Low). Not executable on the audit guest: driver compiled in but no LSI HBA, no /dev/mrsas* (run.log); the structure of the defect (no clearing store exists) is source-certain.