DF-4559 / verdict.json
{ "finding_id": "DF-4559", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED (harness; guest has no LSI mps HBA \u2014 same methodology as DF-4363/DF-1696/DF-1697). sassc->targets is allocated with facts->MaxTargets entries (mps_sas.c:696-697) while the mapping layer hands out target IDs up to max_devices-1 = MaxTargets+MaxVolumes-1 (mps_mapping.c:1733-1734); with IOC pg8 IRVolumeMappingFlags=HIGH the IR volume IDs are exactly [MaxTargets, MaxTargets+MaxVolumes-1] (mps_mapping.c:232-234) and mpssas_volume_add (mps_sas_lsi.c:847-853) writes tid/handle/devname(=fw-controlled u64 wwid)/TAILQ_INIT/SLIST_INIT at targets[id] \u2014 past the end of the allocation. Guard-page harness on the DragonFly guest: voladd-HIGH SIGSEGVs on the first volume write at byte n*sizeof(mpssas_target) of an n*sizeof allocation; removed-HIGH (zeroing branch :310-316) faults at the last slot; LOW-mapping control runs clean; canary run measures 416 bytes clobbered past a 51200-byte allocation spanning [+51200..+52679] with the fw-supplied u64 verified to land at +51208. Fixed-model arm (array sized MaxTargets+MaxVolumes per fix.diff) exits clean \u2014 bad behavior gone. Escalation ceiling honestly noted: constrained-content, fixed-offset overflow; end-to-end in-driver chain not demonstrable without the HBA.", "exploit_chain": "fw/IR config: pg8 IRVolumeMappingFlags=HIGH + any IR volume event (created/online at mps_sas_lsi.c:288/:406, removed at :296-317) -> mapping assigns volume id >= MaxTargets -> &sassc->targets[id] (mps_sas_lsi.c:847/:310) OOB heap writes incl. fw-controlled 8-byte devname=wwid at fixed offset +8 within the slot, 200-byte slots, up to MaxVolumes slots past the end -> adjacent-kernel-heap corruption (panic-grade; controlled-content write primitive proven by canary readback).", "evidence": "run.log/run.2.log: [voladd-HIGH ] KILLED by SIGSEGV ... (OOB write confirmed), [voladd-LOW ] clean exit, [removed-HIGH] KILLED by SIGSEGV, [voladd-HIGH-FIXED] clean exit, canary result: 416 bytes clobbered past the allocation end, spanning [+51200 .. +52679], devname readback ... MATCH: fw-controlled 8B OOB write; VERDICT.md has the full path:line trace.", "kernel_refs": [ "sys/dev/raid/mps/mps_sas_lsi.c:847", "sys/dev/raid/mps/mps_sas_lsi.c:310", "sys/dev/raid/mps/mps_sas_lsi.c:653", "sys/dev/raid/mps/mps_sas_lsi.c:400", "sys/dev/raid/mps/mps_sas.c:696", "sys/dev/raid/mps/mps_sas.c:181", "sys/dev/raid/mps/mps_mapping.c:1733", "sys/dev/raid/mps/mps_mapping.c:232" ], "poc_changes": "No seed PoC existed (pass-2 new finding). Harness written from scratch: faithful x86-64 replica of struct mpssas_target (mps_sas.h:40-79, sizeof=200, offsets printed), replica of the alloc (:697), ID space (:1734), IR maprange (:232-234) and the verbatim write sequences of :848-853 / :311-316; guard-page + canary + fixed-model arms; fork()ed scenarios.", "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": 95, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o df4559 df4559_harness.c", "run_cmd": "./df4559", "code_hash": "b11bae21e04951ad492e837fb8f1c677fc893507bcaa67efc0a57afbae261651", "notes": "Trigger is a SUPPORTED operator config (LSI IR high volume mapping), not only malicious fw. find_target_by_handle (mps_sas.c:181) scanning only [0,MaxTargets) corroborates: volumes invisible to the already added check (mps_sas_lsi.c:400). Informational arm documents the max_devices u16 truncation corner (MaxTargets=65535/MaxVolumes=255 -> start_idx wraps to 0xFFFFFFFF at mps_sas_lsi.c:901) \u2014 malicious-fw only, folded into notes. Guest reset (with-src) after the run.", "recommended_fix": "Size sassc->targets for the full mapping ID space: sassc->maxtargets = facts->MaxTargets + facts->MaxVolumes used in the kmalloc (mps_sas.c:696-697) and in mpssas_find_target_by_handles scan bound (mps_sas.c:181).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Validated with the harness fixed-model arm (voladd-HIGH-FIXED): identical write sequence against MaxTargets+MaxVolumes sizing stays in bounds and exits clean; baseline sizing SIGSEGVs. fix.diff not applied to the read-only sys/ tree; kernel-build validation not meaningful for a harness-verified HBA driver finding (no mps controller in the guest).", "fix_evidence": "run.log lines: [voladd-HIGH ] -> KILLED by SIGSEGV ... (OOB write confirmed) vs [voladd-HIGH-FIXED] -> clean exit (all writes in bounds); fix.diff in pack." } |