DF-4093 / verdict.json
{ "finding_id": "DF-4093", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-certain off-by-one -> heap OOB reads + two 32-byte heap OOB write sinks (CWE-125/CWE-787), mpr twin of DF-4086, not covered by any existing mpr finding (DF-3919 is event element-count walks, not the IR index range). _mapping_get_ir_maprange (mpr_mapping.c:241-255) computes end_idx = start_idx + max_volumes - 1 (:254) unclamped; with firmware facts MaxTargets==0 (max_devices == max_volumes, :2565) plus pg8 RESERVED_TARGETID_0 (:250) and low volume mapping (:248) - all firmware-controlled - end_idx == max_devices. Every IR walk uses inclusive <= and reads mapping_table[max_devices], one 32-byte entry past the kmalloc(max_devices*32) (:2140): :387 (wwid), :430 (handle), :484 (free-idx), :2708 (get_raid_tid, CAM-facing). _mapping_get_free_ir_mt_idx :486 can RETURN the OOB index, and mpr_mapping_ir_config_change_event :3082-3088 then writes a full firmware-controlled entry there (volume WWID, dev_handle, device_info); independently, the _mapping_process_dpm_pg0 volume branch :2260-2271 accepts a DPM DeviceIndex == end_idx and writes the OOB entry at attach time. Harness proves the range math, the OOB reads, the returned OOB index and both 32-byte OOB writes with the fw WWID (run.log). Not reproduced at kernel level: no SAS HBA on the QEMU guest (env.txt), mpr never attaches - same hardware gate as mps twin DF-4086.", "exploit_chain": "Hardware-gated: malicious/buggy IOC facts (MaxTargets=0 + IR + reserved-targetid-0 + low volume mapping) -> volume-add IR config change event -> _mapping_get_free_ir_mt_idx returns max_devices (OOB) when in-range slots are busy -> 32-byte struct write one entry past mapping_table with fw WWID/handle -> adjacent slab-object corruption -> potential kernel code execution; alternatively the same OOB entry is written at boot via a DPM pg0 entry with DeviceIndex == end_idx. Stopped at primitive proof: no HBA in guest.", "evidence": "run.log/run.2.log (guest harness: end==max_devices off-by-one, OOB read at :387, free-idx walk returns 255, event write lands fw WWID at mapping_table[255], DPM volume branch accepts DeviceIndex 255), harness_df4093.c (verbatim range fn + both <= walks + both write sinks), env.txt, VERDICT.md, fix.diff + fix_build.log (-Werror module build)", "kernel_refs": [ "sys/dev/raid/mpr/mpr_mapping.c:241", "sys/dev/raid/mpr/mpr_mapping.c:248", "sys/dev/raid/mpr/mpr_mapping.c:250", "sys/dev/raid/mpr/mpr_mapping.c:254", "sys/dev/raid/mpr/mpr_mapping.c:387", "sys/dev/raid/mpr/mpr_mapping.c:430", "sys/dev/raid/mpr/mpr_mapping.c:484", "sys/dev/raid/mpr/mpr_mapping.c:486", "sys/dev/raid/mpr/mpr_mapping.c:2260", "sys/dev/raid/mpr/mpr_mapping.c:2261", "sys/dev/raid/mpr/mpr_mapping.c:2270", "sys/dev/raid/mpr/mpr_mapping.c:2708", "sys/dev/raid/mpr/mpr_mapping.c:3071", "sys/dev/raid/mpr/mpr_mapping.c:3082", "sys/dev/raid/mpr/mpr_mapping.c:3088", "sys/dev/raid/mpr/mpr_mapping.c:2140", "sys/dev/raid/mpr/mpr_mapping.c:2565" ], "poc_changes": "No seed PoC (fresh twin filing). Harness replicates the mpr range function, the <= walks, the event write :3082-3088 (mpr writes no channel field - struct differs from mps) AND the DPM volume-branch write :2260-2271 (second sink, absent from the mps harness); built/run twice on the guest as an unprivileged user.", "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": 120, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o harness_df4093 harness_df4093.c", "run_cmd": "./harness_df4093", "code_hash": "73d46075d178f1d6dc5fd9ffae80b5cbbfe7c220d270e89cf5a8b1322da82169", "notes": "mpr struct is 32 bytes on amd64 (u16 reserved1 layout variant). _mapping_get_high_missing_mt_idx :358 computes &mapping_table[max_devices+1] in the same fw configuration but never dereferences it - benign, noted. Guest /usr/src restored pristine after the fix build (md5 verified); scratch removed.", "recommended_fix": "Clamp end_idx to sc->max_devices - 1 in _mapping_get_ir_maprange so the inclusive IR walks cannot index past mapping_table.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Applied to the guest /usr/src together with DF-4092s bound-skip; 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-4093/fix.diff, findings/poc/DF-4093/fix_build.log" } |