Divide-by-zero panic if malicious IOC reports RequestFrameSize == 0
Summary
mpt_configure_ioc at mpt.c:2683: mpt->max_seg_cnt*=MPT_NRFM(mpt) = MPT_REQUEST_AREA/MPT_RQSL = .../(RequestFrameSize<<2). If RequestFrameSize==0 from IOC facts -> division by zero -> #DE panic. No validation between facts retrieval (:2654) and use as divisor (:2683). Malicious/buggy HBA. Fix: validate RequestFrameSize!=0 after mpt_get_iocfacts.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1279 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger_analysis.c | trigger-source | documentation marker | 661 B | view raw |
| fix.diff | suggested-fix | validate RequestFrameSize != 0 after mpt_get_iocfacts | 814 B | view raw |
| build.sh | build-script | syntax-checks the marker | 432 B | view raw |
| run.sh | run-script | documents INCONCLUSIVE status | 647 B | view raw |
| combined_build.log | build-log | combined X86_64_GENERIC rebuild log; rc=0 | 5.6 MB | β download |
| env.txt | environment | uname, pciconf -l, kldstat -v | 1015 B | view raw |
| README.md | readme | human-readable summary | 1.8 KB | β raw |
| VERDICT.md | verdict | detailed source-level analysis | 2.2 KB | β raw |
DF-1279 β Divide-by-zero in mpt_configure_ioc (RequestFrameSize == 0)
Finding
In mpt_configure_ioc (sys/dev/disk/mpt/mpt.c:2623), after mpt_get_iocfacts
fills in mpt->ioc_facts (line 2650-2654), the driver computes its segment
limits at line 2683:
mpt->max_seg_cnt *= MPT_NRFM(mpt);
where, from mpt.h:882:
#define MPT_NRFM(mpt) (MPT_REQUEST_AREA / MPT_RQSL(mpt))
#define MPT_RQSL(mpt) (mpt->ioc_facts.RequestFrameSize << 2)
If a malicious or buggy IOC returns IOCFACTS.RequestFrameSize == 0, then
MPT_RQSL(mpt) == 0 and the macro divides MPT_REQUEST_AREA (512) by zero.
The kernel takes a #DE (divide-by-zero) trap and panics. There is no
validation between the facts fetch (line 2654) and the use as a divisor
(line 2683).
Fix
Insert a guard immediately after mpt2host_iocfacts_reply (line 2654): if
RequestFrameSize == 0, log and return EINVAL. Real IOC firmware always
reports a non-zero frame size; the guard only ever fires on a broken or
malicious device.
Verification on this guest
- The mpt driver is in
X86_64_GENERIC, but no MPT HBA is present in the QEMU guest (see DF-1278 README for PCI listing), sompt_configure_iocnever executes. Bug is not runtime-triggerable on this guest. - Source-level confirmation:
mpt.h:876βMPT_RQSL(mpt) = mpt->ioc_facts.RequestFrameSize << 2.mpt.h:882βMPT_NRFM(mpt) = MPT_REQUEST_AREA / MPT_RQSL(mpt).mpt.c:2683βmpt->max_seg_cnt *= MPT_NRFM(mpt);is the divide sink.mpt.c:2654β facts retrieved; no validation between this and line 2683.- Fix verified to compile (combined build with DF-1278/1280/1285/1287).
Realistic impact ceiling
Hardware-attacker (PCIe/Thunderbolt/external chassis) DoS: #DE kernel panic
at attach/hot-plug. Same threat model as DF-1278.
VERDICT β DF-1279
Status
INCONCLUSIVE (source-confirmed; not runtime-triggerable on this guest).
Mechanism (source-confirmed)
mpt_configure_ioc at sys/dev/disk/mpt/mpt.c:2623 retrieves IOC facts at
line 2650-2654:
if (mpt_get_iocfacts(mpt, &mpt->ioc_facts) != MPT_OK) { ... }
mpt2host_iocfacts_reply(&mpt->ioc_facts);
Then computes segment limits at line 2683:
mpt->max_seg_cnt *= MPT_NRFM(mpt);
The macros (mpt.h:876, mpt.h:882):
#define MPT_RQSL(mpt) (mpt->ioc_facts.RequestFrameSize << 2)
#define MPT_NRFM(mpt) (MPT_REQUEST_AREA / MPT_RQSL(mpt))
If a malicious or buggy IOC returns IOCFACTS.RequestFrameSize == 0, then
MPT_RQSL(mpt) == 0 and MPT_NRFM divides MPT_REQUEST_AREA (512) by
zero. The CPU traps #DE and the kernel panics. There is no validation
between line 2654 and line 2683.
Fix
Insert a guard immediately after mpt2host_iocfacts_reply (line 2654):
if RequestFrameSize == 0, log and return EINVAL. Real IOC firmware
always reports a non-zero frame size, so the guard only ever fires on a
broken or malicious device.
Verification on this guest
mptis statically compiled intoX86_64_GENERIC(sys/config/X86_64_GENERIC:93βdevice mpt).- No LSI MPT/Fusion PCI device in
pciconf -l, sompt_configure_iocnever executes. Not runtime-triggerable. - Fix validation: combined
X86_64_GENERICrebuild with this fix applied exitedrc=0. Full log:combined_build.log.
Exploit chain
None. The primitive is a #DE kernel panic at attach time; no userspace
trigger exists on this guest.
Realistic impact ceiling
Hardware-attacker DoS (PCIe / Thunderbolt / external chassis). CVSS:
AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
PoC changes
Folder was empty; added trigger_analysis.c, build.sh, run.sh,
README.md, this VERDICT.md, fix.diff, manifest.json,
combined_build.log.
Recommended fix
Matches the finding proposal: validate mpt->ioc_facts.RequestFrameSize != 0
immediately after mpt2host_iocfacts_reply, returning EINVAL if zero. See
fix.diff.
Fix status
not_testable β bug requires absent hardware. fix.diff applies cleanly
and compiles into X86_64_GENERIC (combined build rc=0).
Fix verification
not_testablecompile validated
nativekernel rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. mpt MPT_NRFM RequestFrameSize=0 -> div-by-zero. mpt in GENERIC, no MPT HW.
No comments yet.