⬢ DragonFlyBSD Kernel Audit
DF-3808 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3808",
  "status": "untested",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-certain structural finding, not PoC-verified (untested): the trigger input is written by the NIC (status-LE TX-index fields / STAT_TXAx_RIDX register), not by packet contents, so it cannot be exercised on the audit guest (no Marvell hardware; NO_MARVELL_PCI, vtnet0 lo0 only; src md5 == audited tree). msk_txeof (sys/dev/netif/msk/if_msk.c:2884-2927) consumes the device-supplied done index with NO range validation: mskc_handle_events feeds it status & STLE_TXA1_MSKL and the port-B composite (if_msk.c:3206-3217) - 11-bit values, 0..4095 - and msk_watchdog feeds a raw 16-bit CSR read (if_msk.c:2671-2674), while the ring holds MSK_TX_RING_CNT = 256 entries (if_mskreg.h:2309). For an idx that can never equal cons (>= 256, or behind cons), the walk terminates only via the msk_tx_cnt <= 0 break (:2901-2902) and therefore force-completes the ENTIRE in-flight window: bus_dmamap_unload + m_freem on mbufs whose TX LEs still carry HW_OWNER (:2910-2916) - the NIC may still be DMA-reading those clusters (stale/freed kernel memory transmitted on the wire, dmamap desync) - and leaves msk_tx_cons advanced to msk_tx_prod while the NIC prefetch unit still walks the old LEs (subsequent msk_encap overwrites hardware-owned descriptors). Memory-safe by construction: the walk is bounded by msk_tx_cnt (<= 256) and MSK_INCs modulo keeps all array access in-bounds; every visited EOP descriptor has a non-NULL tx_m (set at :2575-2579) and m_freem(NULL) is guarded (sys/kern/uipc_mbuf.c) - hence Low severity, device-trust/defense-in-depth class (same trust boundary as DF-3604/DF-3807). fix.diff adds a one-line range check at the top of msk_txeof(), covering both call sites.",
  "exploit_chain": "",
  "evidence": "VERDICT.md (full path:line trace incl. the 0..4095 vs 256 arithmetic and the bounded-drain proof); fix.diff (range check, git apply --check clean); env.txt (no Marvell hardware on guest; untested rationale)",
  "kernel_refs": [
    "sys/dev/netif/msk/if_msk.c:2884",
    "sys/dev/netif/msk/if_msk.c:2900",
    "sys/dev/netif/msk/if_msk.c:2901",
    "sys/dev/netif/msk/if_msk.c:2910",
    "sys/dev/netif/msk/if_msk.c:2671",
    "sys/dev/netif/msk/if_msk.c:3206",
    "sys/dev/netif/msk/if_mskreg.h:2198",
    "sys/dev/netif/msk/if_mskreg.h:2309"
  ],
  "poc_changes": "No PoC authored: hardware-gated device-trust finding (Low severity). Analysis-only pack.",
  "attempts": 0,
  "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": 0,
  "guest_dirty": 0,
  "build_cmd": "",
  "run_cmd": "",
  "code_hash": "32d9b09b23a3ee2822b6f413b4a9d7286f272cd4331e94436666d30826d9c1a9",
  "notes": "Pass-2 finding (pass 1 marked the file clean). Skipped live verification per contract (Low severity, device-trust class, no msk hardware on the audit guest); structural claim is certain from source, impact is speculative (requires faulty/hostile NIC or errant DMA).",
  "recommended_fix": "Range-check the device-supplied done index at the top of msk_txeof(): reject idx < 0 || idx >= MSK_TX_RING_CNT (see fix.diff).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff adds the one-line range check at the top of msk_txeof(), covering both call sites (status LE and watchdog register). Not validated at runtime: requires Yukon hardware to exercise msk_txeof; the change is trivially local and cannot affect the valid-index path.",
  "fix_evidence": "fix.diff"
}