⬢ DragonFlyBSD Kernel Audit
DF-3843 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3843",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Source-certain unbounded firmware-driven OOB write: mrsas_sync_map_info (mrsas.c:3207,3220-3224) copies num_lds = raidMap.ldCount (full u32) 4-byte entries into a fixed 172,200-byte bus_dmamem buffer; the computed bound size_sync_info (mrsas.c:3210) is never used and MR_ValidateMapInfo (mrsas_fp.c:257-265) only checks totalSize/ldCount mutual consistency, both firmware-supplied. On-guest struct-math proof (run.log) shows ldCount=65536 with totalSize=0x9e028a8 passes validation and overwrites 89,944 bytes past the allocation with 3-of-4 firmware-chosen bytes per entry. Kernel-path execution requires a MegaRAID HBA (Thunderbolt/Invader/Fury) or crafted device DMA; the audit guest has the driver compiled in (kldstat: 80 pci/mrsas) but no LSI PCI device and no /dev/mrsas* node, so the trigger surface does not exist in the VM. Hardware-gated; malicious-firmware threat model (same gating as DF-1528/DF-1242..1244, but a write primitive of firmware-chosen length).",
  "exploit_chain": "firmware DMA-authors RAID map with ldCount K>43050 plus consistent totalSize -> attach / AEN-driven map-sync completion (mrsas.c:2965) or OCR (mrsas.c:2477) calls mrsas_sync_map_info -> linear overwrite of kernel memory adjacent to raidmap_mem[] with {u8 targetId, 0x00, u16 seqNum} x K -> heap corruption under firmware control -> kernel code execution. No local unprivileged trigger without the device.",
  "evidence": "run.log lines capacity in sync entries = 43050 and => 89944 bytes written PAST the end of the DMA allocation; VERDICT.md full trace; map_sync_overflow_proof.c struct definitions copied verbatim from mrsas.h; env.txt shows guest has no LSI PCI device / no /dev/mrsas*.",
  "kernel_refs": [
    "sys/dev/raid/mrsas/mrsas.c:3207",
    "sys/dev/raid/mrsas/mrsas.c:3210",
    "sys/dev/raid/mrsas/mrsas.c:3213",
    "sys/dev/raid/mrsas/mrsas.c:3220",
    "sys/dev/raid/mrsas/mrsas.c:3222",
    "sys/dev/raid/mrsas/mrsas.c:3223",
    "sys/dev/raid/mrsas/mrsas.c:1645",
    "sys/dev/raid/mrsas/mrsas_fp.c:257",
    "sys/dev/raid/mrsas/mrsas_fp.c:174",
    "sys/dev/raid/mrsas/mrsas.h:698"
  ],
  "poc_changes": "No seed PoC existed; authored map_sync_overflow_proof.c standalone userland harness (verbatim mrsas.h structs) because the kernel path needs an HBA the guest does not have.",
  "attempts": 1,
  "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": 42,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o /tmp/df3843_proof /tmp/df3843_proof.c",
  "run_cmd": "/tmp/df3843_proof; kldstat -v | grep -i mrsas; pciconf -lv | grep -i megaraid; ls /dev/mrsas*",
  "code_hash": "f7c6391d30a3486b0c0096990c974f92b93112aac2841d3d88a8608a954f6fa6",
  "notes": "Hardware-gated (malicious/broken firmware or device DMA). Driver present in guest kernel config sys/config/X86_64_GENERIC:123 and kldstat, but never attaches without the HBA. 22,486 fully-OOB entries at ldCount=65536; loop also OOB-reads the source map via MR_LdRaidGet/MR_GetLDTgtId (ldSpanMap[i], i unbounded). Same threat gating as accepted findings DF-1242/1243/1244/1528 but strictly stronger primitive (arbitrary-length linear write vs single-slot or read-only).",
  "recommended_fix": "Reject ldCount > MAX_LOGICAL_DRIVES in mrsas_sync_map_info before the copy loop (release the mfi cmd and return error) and add the same bound to MR_ValidateMapInfo so bogus maps never enable fast path.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff bounds ldCount at both the sync path (mrsas.c) and validation (mrsas_fp.c); cannot be boot-tested on this guest (no HBA), so fix validation is not_testable rather than fixed. The bound provably removes the only writer of the overflow: the loop cannot execute past MAX_LOGICAL_DRIVES iterations after the guard.",
  "fix_evidence": "fix.diff hunks; map_sync_overflow_proof.c capacity math (43050 entries capacity vs MAX_LOGICAL_DRIVES=64 bound)."
}