DF-4092 / verdict.json
{ "finding_id": "DF-4092", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-certain heap OOB write (CWE-787), mpr twin of DF-4085. In _mapping_process_dpm_pg0 (sys/dev/raid/mpr/mpr_mapping.c:2273-2347), DPM entries whose DeviceIndex falls in the direct-attached range take num_slots = max_num_phy_ids (:2290), the firmware u16 ioc_pg8.MaxNumPhysicalMappedIDs (:2216), never validated against the mapping-table size; the reservation loop :2327-2347 then writes num_slots consecutive 32-byte struct dev_mapping_table entries (mprvar.h:113, verified 32 bytes on amd64) with no check that dev_idx+num_slots <= max_devices (kmalloc(max_devices*32) at :2140-2141, max_devices = MaxTargets+MaxVolumes at :2565). With an IN-BOUNDS dev_idx (distinct from DF-3914s event-NumSlots path and DF-3915s commit_enc_entry path) a malicious/buggy IOC or emulated HBA gets a boot-time heap overflow: harness proves 65,281 entries (2,088,992 bytes) past a 16,320-byte allocation in the worst case, firmware-controlled qword at stride 32 - while modeling the per-entry dpm_entry_num==MPR_DPM_BAD_IDX conflict gate verbatim (in-bounds entries always pass; each OOB block is OOB-read and written iff its garbage u16 at offset 16 is 0xFFFF, e.g. a stale adjacent mapping table from a previous attach cycle). Not reproduced at kernel level: no SAS HBA on the QEMU guest (env.txt), mpr never attaches - same hardware gate as DF-3914/DF-3915 and mps twin DF-4085. Primitive proven at object level on the guest (run.log/run.2.log, identical across runs).", "exploit_chain": "Hardware-gated chain (not executable on this guest): malicious/compromised IOC firmware or PCI-passthrough emulated HBA -> IOC pg8 MaxNumPhysicalMappedIDs=0xFFFF + DPM pg0 entry with in-bounds DeviceIndex -> mpr_mapping_initialize -> _mapping_process_dpm_pg0 reservation loop -> linear heap overwrite (up to ~2MB) with fw-controlled qwords at 32-byte stride past mapping_table into adjacent kmalloc zones -> slab metadata / neighboring object corruption -> kernel code execution. Stopped at primitive proof: no HBA in guest.", "evidence": "run.log/run.2.log (guest harness: conflict-gated canary smash, 131,072-byte groomed run and 2,088,992-byte worst case at stride 32, in-bounds dev_idx), harness_df4092.c (verbatim struct mprvar.h:113 + loop :2327-2347 incl. goto-fail gate), env.txt (hardware gate), VERDICT.md (line-by-line chain), fix.diff + fix_build.log (-Werror module build with both mpr fixes, mpr.ko linked)", "kernel_refs": [ "sys/dev/raid/mpr/mpr_mapping.c:2216", "sys/dev/raid/mpr/mpr_mapping.c:2284", "sys/dev/raid/mpr/mpr_mapping.c:2290", "sys/dev/raid/mpr/mpr_mapping.c:2327", "sys/dev/raid/mpr/mpr_mapping.c:2328", "sys/dev/raid/mpr/mpr_mapping.c:2140", "sys/dev/raid/mpr/mpr_mapping.c:2565", "sys/dev/raid/mpr/mpr_mapping.c:2593", "sys/dev/raid/mpr/mpr_mapping.c:2627", "sys/dev/raid/mpr/mprvar.h:113" ], "poc_changes": "No seed PoC (fresh twin filing). Harness authored against the exact mpr struct layout (32 bytes on amd64, layout differs from mps: u16 reserved1 instead of u8 reserved1+u8 channel) with the verbatim :2327-2347 loop INCLUDING the dpm_entry_num!=MPR_DPM_BAD_IDX goto-fail gate that the mps DF-4085 harness omitted; three adjacent-heap scenarios; built and run twice on the audit guest with cc 8.3 as an unprivileged user (first iteration fixed a uint16 truncation in the scenario-C guard count).", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 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": 150, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o harness_df4092 harness_df4092.c", "run_cmd": "./harness_df4092", "code_hash": "033421f892dd3454f451af02ca98f7cc43e3f7a4d4550de0515f18d316b0f05c", "notes": "Cross-apply from the mps batch: struct is 32 bytes on amd64 in mpr too, so the mps magnitude analysis carries over. Guest /usr/src restored pristine after the fix build (md5 0dfb1866c50fa4c6d15f607acd7d729d verified, reverse-patch, no artifacts); guest tmp scratch removed.", "recommended_fix": "In _mapping_process_dpm_pg0, skip any DPM entry with dev_idx >= max_devices or num_slots > max_devices - dev_idx before storing into enclosure_table or running the reservation loop.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Applied to the guest /usr/src together with DF-4093s clamp; make in sys/dev/raid/mpr compiled all sources with -Werror and linked mpr.ko (BUILD_EXIT=0). Runtime fix validation not testable: the path requires an mpr(4) HBA delivering firmware pages, absent on this guest.", "fix_evidence": "findings/poc/DF-4092/fix.diff, findings/poc/DF-4092/fix_build.log" } |