DF-4868 / verdict.json
{ "finding_id": "DF-4868", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "mps_print_sgl(), reached unconditionally and ungated (raw kprintf, no sc->mps_debug check) from mps_scsiio_complete on any MPI2_IOCSTATUS_INVALID_SGL completion (mps_sas.c:2063 -> mps_table.c:495), walks the request-frame SGL with no per-frame bound (sge++, mps_table.c:471), dereferences chain->chain without a NULL check (mps_table.c:482) — and unlike the mpr twin the chain deref sits in the only walk, so a plain chainless command with an empty cm_chain_list (mps.c:859) panics on the first stale LAST_ELEMENT (0x80) flag — and hexdumps a fixed 128 bytes for both the request frame (mps_table.c:462) and chain frames (mps_table.c:484) regardless of the IOC-facts IOCRequestFrameSize*4 frame size (mps.c:750/:821). With a buggy or malicious controller this is an OOB heap read printed to console plus a NULL-deref panic (local DoS); no write primitive. Not exercised on the audit guest: it is a virtio-only KVM guest with no LSI MPT2 device, the mps driver never attaches (env.txt), and the IOC status cannot be produced. Verified by line-accurate code tracing.", "exploit_chain": "", "evidence": "README.md (trigger analysis), VERDICT.md (full trace incl. chain-list lifecycle), env.txt (guest has no vendor 0x1000 device, no hw.mps sysctls), fix.diff (chain NULL guard + per-frame walk cap + bounded hexdumps)", "kernel_refs": [ "sys/dev/raid/mps/mps_table.c:459", "sys/dev/raid/mps/mps_table.c:462", "sys/dev/raid/mps/mps_table.c:473", "sys/dev/raid/mps/mps_table.c:482", "sys/dev/raid/mps/mps_table.c:484", "sys/dev/raid/mps/mps_table.c:495", "sys/dev/raid/mps/mps_sas.c:2063", "sys/dev/raid/mps/mps.c:859", "sys/dev/raid/mps/mps.c:1808" ], "poc_changes": "no runnable PoC produced: requires Fusion-MPT2 hardware returning INVALID_SGL; audit guest has none (env.txt)", "attempts": 0, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 0, "guest_dirty": 0, "build_cmd": "", "run_cmd": "", "code_hash": "", "notes": "Direct sibling of DF-4789 (mpr twin, same pass-set); delta: in mps the chain deref is in the single walk, so it is on the default INVALID_SGL path, not only the IEEE path. Same class/trust boundary as pass-1 DF-3816/DF-3817 (debug-path OOB reads, Low). The walked SGL is driver-built, so the trigger requires firmware misbehavior or DMA corruption; severity stays Low for that reason.", "recommended_fix": "Break the walk when the chain list is exhausted, cap SGEs walked per IOC-facts frame size, and bound the hexdumps (see fix.diff)", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "mechanical guards (NULL break + iteration caps + bounded hexdump); cannot be boot-validated without mps hardware in the guest", "fix_evidence": "findings/poc/DF-4868/fix.diff" } |