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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1279 Β· 8 files
FileTypeDescriptionSize
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
README.md readme human-readable summary
↓ download 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), so mpt_configure_ioc never 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.md verdict detailed source-level analysis
↓ download raw

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

  • mpt is statically compiled into X86_64_GENERIC (sys/config/X86_64_GENERIC:93 β€” device mpt).
  • No LSI MPT/Fusion PCI device in pciconf -l, so mpt_configure_ioc never executes. Not runtime-triggerable.
  • Fix validation: combined X86_64_GENERIC rebuild with this fix applied exited rc=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.

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_testable

compile 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.