MFI_CMD ioctl: devclass_get_softc() result used without NULL check -> one-ioctl kernel NULL-deref panic
Summary
mfi_ioctl MFI_CMD takes mfi_adapter_no (user uint16) and does sc = devclass_get_softc(devclass, adapter) with no NULL check; any adapter number >= the installed count returns NULL and the next statement (lockmgr) writes through NULL+offset -> panic. The Linux shim paths check NULL; only the native path omits it. Local DoS by any user who can open /dev/mfi0 (0640 root:operator) on a host with an mfi adapter - one ioctl. NULL-check fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3871 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.2 KB | β raw | |
| VERDICT.md | β | 1.1 KB | β raw | |
| build.sh | β | 106 B | view raw | |
| env.txt | β | 283 B | view raw | |
| fix.diff | β | 484 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-3871 β mfi_ioctl MFI_CMD: devclass_get_softc NULL not checked -> kernel NULL deref panic
mfi_ioctl() MFI_CMD path, sys/dev/raid/mfi/mfi.c:2953-2962:
adapter = ioc->mfi_adapter_no; /* user, uint16 */
if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
devclass = devclass_find("mfi");
sc = devclass_get_softc(devclass, adapter); /* NULL for adapter >= units */
}
lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); /* NULL deref */
devclass_get_softc() (subr_bus.c:950) returns NULL for any out-of-range or
sparse unit. With exactly one adapter, every mfi_adapter_no in 1..65535
yields NULL, and the very next statement writes through &sc->mfi_io_lock
(fault near NULL -> trap_fatal -> panic). The Linux ioctl shim checks NULL
(mfi.c:3146-3147 and 3167); only the native MFI_CMD path lacks it.
Reach: any user able to open /dev/mfi0 (0640 root:operator) on a host with
an mfi(4) adapter β trivial one-ioctl local DoS.
Build/run
cc -O2 -o mfi_ioctl_nullderef mfi_ioctl_nullderef.c # trigger 1 = this finding ./mfi_ioctl_nullderef
On hardware: kernel panics at the lockmgr. On the audit guest (no MegaRAID): open() fails ENOENT -> hardware-gated (run.log).
DF-3871 VERDICT β inconclusive (hardware-gated), source-certain
- Code path verified line-by-line: mfi.c:2953-2962 (lookup), subr_bus.c:950-958 (NULL for out-of-range unit), mfi.c:2958 (lockmgr through NULL sc).
- The sibling Linux shim paths DO NULL-check (mfi.c:3146-3147, 3167-3168), which is direct evidence the check was simply forgotten in the native path.
- PoC builds and runs on the guest;
/dev/mfi0absent (no MegaRAID controller) so the kernel path cannot fire here β run.log records the ENOENT. - Trigger is one ioctl with
mfi_adapter_no=1on any real mfi host; write to near-NULL in kernel mode -> trap_fatal -> panic. Impact: local DoS by any user with the device open (operator group). - fix.diff adds the same NULL check the Linux shim already has.
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_testableadd the same NULL check the Linux shim has
fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
DF-3871/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 mfi_adapter_no >= adapter count makes devclass_get_softc() return NULL (subr_bus.c:950-958) and mfi.c:2958 lockmgr's through &sc->mfi_io_lock -> kernel NULL-deref panic from a single ioctl; the Linux shim paths null-check (mfi.c:3146,3167), the native path does not. Device 0640 root:operator. Guest has no MegaRAID (run.log): hardware-gated, source-certain.
No comments yet.