mfi_check_for_sscd() dereferences NULL cm_data on MFI_CMD DCMD CFG_ADD with zero data_len (and heap-OOB-reads short buffers, bypassing pre/post checks)
Summary
mfi_ioctl calls mfi_check_for_sscd() for every MFI_CMD before validating the command. With a user frame opcode=MFI_DCMD_CFG_ADD, data_len=0 and no DATAIN/DATAOUT flags, cm->cm_data stays NULL; mfi_check_for_sscd then evaluates conf_data->ld[0].params.isSSCD - a read at NULL+~2.5KB -> panic before any firmware round-trip. With a small nonzero data_len the same expression is a heap OOB read whose garbage result can set skip_pre_post=1 and bypass mfi_check_command_pre/post for CFG_ADD. Local DoS + pre/post-check bypass by any operator-group user via one ioctl; no firmware cooperation needed. NULL+length-guard fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3872 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.2 KB | β raw | |
| VERDICT.md | β | 1.2 KB | β raw | |
| build.sh | β | 106 B | view raw | |
| env.txt | β | 283 B | view raw | |
| fix.diff | β | 607 B | view raw | |
| mfi_ioctl_nullderef.c | β | 4.2 KB | view raw | |
| run.log | β | 264 B | view raw | |
| run.sh | β | 102 B | view raw |
DF-3872 β mfi_check_for_sscd() dereferences NULL cm_data (MFI_CMD, DCMD CFG_ADD, data_len=0)
mfi.c:3040 calls skip_pre_post = mfi_check_for_sscd(sc, cm); for every
MFI_CMD ioctl before the pre/post command checks. Inside (mfi.c:2677-2685):
struct mfi_config_data *conf_data = cm->cm_data;
...
if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) &&
(conf_data->ld[0].params.isSSCD == 1)) {
With a user frame of cmd=MFI_CMD_DCMD, opcode=MFI_DCMD_CFG_ADD (0x04020000),
data_len=0 and no DATAIN/DATAOUT flags, mfi.c:2996-3002 leaves
cm->cm_data = 0, so conf_data->ld[0].params.isSSCD reads at
NULL + offsetof(mfi_config_data, ld[0].params.isSSCD) (~2.5 KB, past
array[MFI_MAX_ARRAYS]) β kernel read of unmapped low memory ->
trap_fatal -> panic. Single ioctl, no firmware roundtrip needed.
Secondary: with a small-but-nonzero data_len (< offsetof(ld[0])), the same
expression is a heap OOB read whose garbage value can force skip_pre_post=1,
bypassing mfi_check_command_pre/post for CFG_ADD.
Build/run
cc -O2 -o mfi_ioctl_nullderef mfi_ioctl_nullderef.c # trigger 2 = this finding ./mfi_ioctl_nullderef
Guest has no MegaRAID -> hardware-gated (run.log).
DF-3872 VERDICT β inconclusive (hardware-gated), source-certain
- Verified: mfi.c:2996-3002 (
cm->cm_data = 0when cm_len==0 or no data flags β note the "legacy app shim" at 2990 only sets the FLAGS, not a buffer), mfi.c:3040 (unconditional call), mfi.c:2679 + 2684-2685 (NULL deref guarded only by the opcode compare β short-circuit does NOT save the CFG_ADD case), mfireg.hMFI_DCMD_CFG_ADD = 0x04020000,mfi_config_datalayout (size/array_count/spare_count/array[16]/ld[64] -> ld[0] ~2.5 KB in). - The read faults in kernel mode on an unmapped low address -> panic; nothing firmware-dependent happens before the fault (no roundtrip).
- Guest: no /dev/mfi* (run.log) -> kernel path not exercisable; code-level certainty high: this is a straight missing-NULL/OOB guard on a user ioctl.
- fix.diff checks conf_data != NULL and data_len covering ld[0].
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_testablerequire conf_data != NULL and cm_len covering ld[0] in mfi_check_for_sscd
fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
DF-3872/run.log (build OK, device absent) + VERDICT.md line-by-line trace
PoC changes
written fresh; shared trigger binary covers DF-3871 (T1), DF-3872 (T2), DF-3873 (T3)
Verified recommended fix
mfi_ioctl_nullderef.c
Verdict
MFI_CMD with cmd=MFI_CMD_DCMD, opcode=MFI_DCMD_CFG_ADD, data_len=0 leaves cm->cm_data NULL (mfi.c:2996-3002); mfi_check_for_sscd (mfi.c:3040 -> 2679,2684-2685) then evaluates conf_data->ld[0].params.isSSCD at NULL+~2.5K -> kernel fault -> panic, before any firmware round-trip. Small nonzero data_len instead gives a heap OOB read that can bypass pre/post checks (skip_pre_post=1). Guest has no MegaRAID: hardware-gated, source-certain.
No comments yet.