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

Unbounded waits and ignored reinit errors: mps_wait_command(...,0) sleeps forever, mps_reinit ignores mps_reregister_events() failure leaving the simq frozen permanently

Summary

(1) mps_wait_command with timeout==0 sleeps indefinitely; mps_read_config_page passes 0 - a silent-but-not-faulted IOC (watchdog reinitializes only on FAULT) hangs the config thread forever. (2) mps_reinit discards reregister_events' return; on failure mpssas_startup never fires so the simq frozen in handle_reinit is never released - all adapter I/O wedged until reboot. (3) reregister_events treats EINPROGRESS as failure although the async callback still completes - entering the wedge spuriously. Finite-timeout + honor-error + accept-EINPROGRESS fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4078 Β· 5 files
FileTypeDescriptionSize
verdict.json β€” 2.2 KB view raw
README.md β€” 332 B ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
fix.diff β€” 651 B view raw
manifest.json β€” 720 B view raw

DF-4078 β€” mps unbounded waits and ignored reinit errors can wedge the adapter permanently

Files/lines: mps.c:2129 + :2221 (infinite lksleep), :353 (ignored mps_reregister_events error), :1769-1772 (EINPROGRESS treated as failure); mps_sas.c:1091 (frozen simq) Source-level finding; chip-gated DoS. See VERDICT.md.

VERDICT.md
↓ download raw

DF-4078 VERDICT β€” source-level likely, chip-gated (permanent I/O hang / thread hang)

(1) Indefinite sleep with timeout == 0

mps_wait_command():2129 lksleep(cm, &sc->mps_lock, 0, "mpswait", timeout*hz) β€” with timeout 0 DragonFly sleeps forever. mps_read_config_page():2221 passes 0. A silent-but-not-faulted IOC (the periodic watchdog calls mps_reinit only on MPI2_IOC_STATE_FAULT, mps.c:1247-1252) hangs the config-path thread indefinitely (attach / CAM contexts).

(2) mps_reinit ignores mps_reregister_events() failure

mps_reinit():353 calls mps_reregister_events(sc) and discards the return. On failure (mps_alloc_command EBUSY from an exhausted pool, or bus_dmamap_load error) the completion that would call mpssas_startup() (mps_reregister_events_complete:1654) never fires; the simq frozen in mpssas_handle_reinit (mps_sas.c:1091 xpt_freeze_simq) is never released β‡’ every I/O on the adapter wedges until reboot.

(3) EINPROGRESS mishandled

mps_reregister_events():1769-1772 treats mps_map_command() EINPROGRESS as a failure return, though the async DMA-map callback will still enqueue and complete the request β€” a spurious entry into exactly the failure path of (2).

DoS only; no memory corruption. Confidence 'likely' (needs a misbehaving/exhausted IOC+pool state).

Fix

Finite timeout at :2221; check and retry/fail loudly on :353; accept EINPROGRESS at :1769.

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

Hardware-gated finding (no AMD VegaM GPU / no LSI mps controller on the audit guest): fix authored at source level (fix.diff) but not build/boot-validated.

fix.diff in this pack; authored post-analysis, not hardware-validated.
↓ fix.diffper-fix-DF-4078

Confirmed kernel references

Detail

Evidence (decisive lines)

mps.c:2129 lksleep with timeout*hz; :2221 caller passes 0; :353 unchecked mps_reregister_events(); mps_sas.c:1091 xpt_freeze_simq

PoC changes

n/a (source-level)

Verified recommended fix

Pass a finite timeout at :2221; check and act on mps_reregister_events() failure (retry or fail the reinit); treat EINPROGRESS as success in mps_reregister_events().

Verdict

Source-level likely, chip-gated permanent hangs. (1) mps_wait_command():2129 does lksleep(cm, ..., timeout*hz); mps_read_config_page() passes timeout == 0 at :2221 => indefinite sleep. A silent-but-not-faulted IOC (periodic watchdog only calls mps_reinit on MPI2_IOC_STATE_FAULT) hangs the config-path thread forever. (2) mps_reinit():353 ignores the return of mps_reregister_events(); if it fails (EBUSY from an exhausted command pool, or bus_dmamap_load error), the completion that would call mpssas_startup() never fires, so the simq frozen in mpssas_handle_reinit (mps_sas.c:1091) is never released => all adapter I/O wedged until reboot. (3) mps_reregister_events():1769-1772 treats mps_map_command() EINPROGRESS as a failure although the async map callback will still enqueue and complete the request, needlessly entering that failure path.