mfi_syspd_dump acknowledges every crash-dump chunk the firmware rejected β polled transport returns 0 for any firmware cmd_status, so a dead/removed system PD 'successfully' dumps an empty core (DF-5027 shape)
Summary
The polled mfi_send_frame returns 0 for ANY non-timeout firmware status and the dump path never inspects cmd_status/scsi_status afterwards (contrast mfi_bio_complete which checks both) - a faulted PD completes-but-rejects every WRITE_10 while do_dump records chunk success; savecore believes an empty core. Identical class to DF-5027 (ips); the mfi_disk LD twin shares the omission. cmd_status re-check fix compile-validated.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5050 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.7 KB | β raw | |
| VERDICT.md | β | 3.3 KB | β raw | |
| env.txt | β | 394 B | view raw | |
| fix.diff | β | 1.3 KB | view raw | |
| manifest.json | β | 969 B | view raw | |
| verdict.json | β | 2.6 KB | view raw |
DF-5050 β mfi_syspd_dump acknowledges dump chunks the firmware rejected
What this is
mfi_syspd_dump (sys/dev/raid/mfi/mfi_syspd.c:287-309) forwards crash-dump
writes to mfi_dump_syspd_blocks (mfi.c:2439-2484) and returns its error.
But the polled transport (mfi_send_frame, mfi.c:2273-2323) returns 0 for
any firmware completion status β it only fails on timeout
(cmd_status == MFI_STAT_INVALID_STATUS, mfi.c:2316-2320). Neither
mfi_dump_syspd_blocks nor mfi_syspd_dump ever inspects
pass->header.cmd_status / scsi_status afterwards.
So when the firmware completes-but-rejects every WRITE_10 (dead, removed or
faulted system PD β exactly the state you are likely crash-dumping through),
every 64K chunk of the "dump" is reported success without a byte written.
do_dump/savecore then record and restore an empty/corrupt core dump. Same
shape as DF-5027 (ips(4)), here on the mfi syspd path; the LD twin
(mfi_dump_blocks, mfi.c:2437ff) shares the omission and belongs to the
mfi_disk family follow-up.
Reproduce
No userland trigger exists β the sink is the kernel crash-dump path. On
hardware: configure dumpdev=/dev/mfisyspdN, fault/remove the PD, panic the
system β dump "succeeds", savecore produces a garbage/missing core. On this
QEMU guest there is no MegaRAID controller at all (env.txt), so the path is
unreachable β the source chain is deterministic and cited in VERDICT.md.
Fix
fix.diff β after the DMA unload in mfi_dump_syspd_blocks, check
pass->header.cmd_status != MFI_STAT_OK || scsi_status != 0 and return EIO so
do_dump aborts instead of recording fake success. Compile-validated on
stock X86_64_GENERIC (make nativekernel clean).
VERDICT β DF-5050
Status: not_reproduced (hardware-gated β no MegaRAID controller on the audit guest; the sink is the kernel crash-dump path, which additionally requires a panic). Deterministic source chain. Fix compile-validated. Confidence in the bug: certain (every link is a direct path:line read; no race, no speculation).
Source chain
- Crash dump writes to a syspd dump device route to
mfi_syspd_dump(mfi_syspd.c:287-309); forlen > 0it callsmfi_dump_syspd_blocks(parent_sc, sc->pd_id, offset / MFI_SECTOR_LEN, virt, len)(mfi_syspd.c:301-304). mfi_dump_syspd_blocks(mfi.c:2439-2448, 2451-2484) builds aMFI_CMD_PD_SCSI_IOWRITE_10 pass frame withcm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT(2475) and callsmfi_mapcmd(2477), then returnserror(2483) β the transport error only. It never reads backpass->header.cmd_statusorpass->header.scsi_status.mfi_mapcmd(mfi.c:2152-2175) βmfi_send_frame(mfi.c:2273-2323). For a POLLED command it pre-setshdr->cmd_status = MFI_STAT_INVALID_STATUS(2284), issues, busy-waits (2309-2314) and: * timeout β returns ETIMEDOUT (2316-2320); * any other firmware status β including MFI_STAT_FAILED, MFI_STAT_*, SCSI check conditions (scsi_status != 0) β returns 0 (2322). The firmware's actual verdict is only visible inhdr->cmd_status/hdr->scsi_status, which the dump path never consults (contrast the normal I/O completionmfi_bio_complete, mfi.c:2103-2108, which does check both).- Consequently
mfi_syspd_dumpreturns 0 for every chunk (mfi_syspd.c:304, 308) anddo_dump's write loop believes the whole core was persisted.
Concrete failing scenario: system disk(s) on a healthy volume, dumpdev on a raw system PD; the PD dies (or was hot-removed β MR_EVT_PD_REMOVED, and note DF-5049: the syspd may still be present and openable after removal); panic; firmware completes each WRITE_10 with a failure status; driver reports success; savecore resurrects an empty/partial dump and the operator loses the crash evidence. Availability/integrity only (C:N/I:L/A:N) β the DF-5027 class.
Guest evidence
- No MegaRAID PCI device, no /dev/mfisyspd* (env.txt) β path unreachable on this guest; no runtime reproduction possible, by hardware gate.
fix.diffapplied to the guest /usr/src copy;make -DNO_CLEAN nativekernel KERNCONF=X86_64_GENERICβ "Kernel build for X86_64_GENERIC completed", exit 0; source reverted and verified byte-identical afterwards. Baseline behavior not exercisable β fix validation is compile-level only (fix_status not_testable).
Notes
- The
len == 0branch ofmfi_syspd_dump(mfi_syspd.c:305-307) is the upstream-inherited no-op "sync cache" β noted, but the real integrity bug is the per-chunk fake success above. - LD twin:
mfi_dump_blocks(mfi.c:2437ff) +mfi_disk_dump(mfi_disk.c:322-345) have the identical omission; left to the mfi_disk family fix to keep this diff scoped to the syspd finding.
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_testablefix.diff applied cleanly on the guest /usr/src copy and compile-validated (make -DNO_CLEAN nativekernel KERNCONF=X86_64_GENERIC -> completed, exit 0); source reverted and verified byte-identical. Dump-path behavior not exercisable without hardware.
VERDICT.md guest-evidence section
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md source chain (path:line for all four links incl. the contrast with mfi_bio_complete which DOES check cmd_status); env.txt hardware absence; fix.diff compile validation
PoC changes
No seed PoC; none possible (kernel crash-dump path). Pack documents the source chain instead.
Verified recommended fix
After mfi_mapcmd in mfi_dump_syspd_blocks, fail with EIO when pass->header.cmd_status != MFI_STAT_OK || scsi_status != 0 (see fix.diff)
Verdict
Hardware-gated: the sink is the kernel crash-dump path and the guest has no MegaRAID controller (env.txt), so no runtime reproduction was possible. The source chain is deterministic: mfi_syspd_dump (mfi_syspd.c:301-304) forwards dump writes to mfi_dump_syspd_blocks (mfi.c:2477), whose polled transport mfi_send_frame returns 0 for ANY firmware completion status except timeout (mfi.c:2316-2322) β the dump path never re-checks pass->header.cmd_status/scsi_status, so firmware-rejected WRITE_10s (dead/removed/faulted PD) are acknowledged chunk-by-chunk and savecore believes an empty/corrupt dump. DF-5027 shape on the mfi syspd path.
No comments yet.