{
  "finding_id": "DF-5141",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "mlx_pci_attach() calls mlx_free(sc) a second time on the mlx_attach()-failure path (mlx_pci.c:204) even though mlx_attach() already performs a complete teardown on every one of its 10 error exits (mlx.c:308-453); mlx_free() NULLs no pointers, so the second call re-executes kfree(mlx_enq2), double bus_dma_tag_destroy, double bus_dmamem_free, double IRQ/register-window release on freed, re-ownable objects. Proven on the guest with the running kernels real mlx_free(): the exact two-call sequence panics with memory chunk ... is already free! (stack: chunk_mark_free <- _kfree <- bus_dma_tag_destroy <- mlx_free), and an ordinary kmalloc between the two frees took ownership of the mlx_enq2 block (v1 == enq2 pointer), demonstrating a true double-free/UAF of live-owned kernel heap rather than a benign re-free. Entry path is hardware-gated (needs a Mylex DAC960 PCI controller plus an attach failure: IRQ alloc/setup failure, DMA tag failure, s/g map failure, ENQUIRY2/ENQUIRY_OLD failure, firmware handshake error) \u2014 no unprivileged trigger exists, so uid=0 escalation is not applicable; realistic ceiling on affected hardware is boot-time kernel heap corruption/panic.",
  "exploit_chain": "n/a for user-driven exploitation (trigger is driver-internal error handling at boot/module-load on Mylex hardware, not attacker-controlled input). Demonstrated primitive chain: mlx_attach() error -> mlx_free() #1 (clean teardown; freed chunks return to the live allocator) -> [any kernel allocation may take ownership, shown: kmalloc(128,M_DEVBUF) returned the just-freed mlx_enq2 block] -> mlx_pci.c:204 mlx_free() #2 -> kfree/bus_dma_tag_destroy on already-freed/re-owned memory -> allocator double-free detection panic (or, if the chunks were reused, silent slab corruption).",
  "evidence": "run.log/panic.txt: panic text + stack through the kernels mlx_free; the v1=0xfffff800897a5000 owns the freed block: YES line proves re-ownership between the frees (enq2=0xfffff800897a5000 from the first DF5141 line). fix_run.log: patched-kernel run of df5141f.ko (fixed single-free sequence) completes and unloads cleanly. fix_build.log: patched mlx_pci.o has 2 mlx_free call sites vs 3 in stock /boot/kernel.old mlx_pci_attach. build.log: -Werror-clean module build. env.txt: guest kernels (stock #0 Jul 2 / patched #1 Sep 30), no Mylex PCI device on guest, source md5 sync.",
  "kernel_refs": [
    "sys/dev/raid/mlx/mlx_pci.c:202-206",
    "sys/dev/raid/mlx/mlx.c:149-193",
    "sys/dev/raid/mlx/mlx.c:308",
    "sys/dev/raid/mlx/mlx.c:333",
    "sys/dev/raid/mlx/mlx.c:348",
    "sys/dev/raid/mlx/mlx.c:356",
    "sys/dev/raid/mlx/mlx.c:373",
    "sys/dev/raid/mlx/mlx.c:383",
    "sys/dev/raid/mlx/mlx.c:397",
    "sys/dev/raid/mlx/mlx.c:410",
    "sys/dev/raid/mlx/mlx.c:443",
    "sys/dev/raid/mlx/mlx.c:453"
  ],
  "poc_changes": "No seed existed (orchestrator reserved fresh IDs). Harness authored from scratch: KLD module calling the kernels real mlx_free(); had to (1) copy mlx_compat/io/var/reg headers next to the module because CFLAGS include paths are rebuilt by bsd.kmod.mk, (2) add generated device_if.h/bus_if.h/pci_if.h to SRCS, (3) include sys/disk.h+sys/devicestat.h for mlxvar.hs mlxd_softc, (4) drop MODULE_DEPEND(df5141,mlx,...) \u2014 in-kernel mlx registers as pci/mlx so the KLD linker refused the dependency, (5) use a real pci0 device_t for mlx_dev, (6) transfer via openssl base64 through the ssh-stdin shell (guest /bin/sh truncates >1KB lines).",
  "attempts": 3,
  "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": 1,
  "build_cmd": "cd /tmp/df5141 && make SYSDIR=/usr/src/sys   (KLD df5141.ko, -Werror clean)",
  "run_cmd": "kldload /tmp/df5141/df5141.ko",
  "code_hash": "8c7548721900562dc3c5049bed0431160d155ec6b73084f9e5ec3cc21dbcfe06",
  "notes": "Guest left in ddb by the decisive run and later reset with vm.sh reset with-src (final state: clean-source snapshot, guest up). Fix validated on a rebuilt kernel (see fix fields). Severity Low per rubric (requires specific hardware + attach failure; no unprivileged trigger) but memcorrupt bucket with a proven double-free primitive. Binary-level fix proof: stock mlx_pci_attach=3 mlx_free calls, patched=2.",
  "recommended_fix": "Remove the redundant mlx_free(sc) at sys/dev/raid/mlx/mlx_pci.c:204 (mlx_attach() already tears down fully on every error return).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Wed Sep 30 07:26:18 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_verdict": "fix.diff (one line: delete mlx_free(sc) from the mlx_attach()-failure branch) applied to the guests pristine /usr/src, kernel rebuilt with make -j6 nativekernel (RC=0, -Werror clean), installed and booted (kernel #1 Sep 30 07:26:18). Baseline (stock #0): bug-sequence run panics with double-free detection. Patched: the fixed-caller sequence (df5141f.ko, identical harness minus the removed second call) runs clean \u2014 no panic, no aliasing, module loads AND unloads, guest stays up. Caller-side fix means the harnesss emulation of the caller is updated to match the patched caller; corroborated objectively: patched mlx_pci.o contains 2 mlx_free call relocations vs 3 in the stock kernels mlx_pci_attach, so the shipped driver can no longer perform the double teardown.",
  "fix_evidence": "fix.diff; fix_run.log (DF5141F RESULT=CLEAN lines); fix_build.log (build RC=0, kernel #1 artifacts, objdump call counts 3->2); fix_poc_build.log (df5141f.ko build); env.txt (both unames)."
}