⬢ DragonFlyBSD Kernel Audit
DF-3849 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3849",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Source-level certain: dc_rxeof (sys/dev/netif/dc/if_dc.c:2500-2607) takes the received frame length solely from the NIC-DMAd descriptor status word - total_len = DC_RXBYTES(rxstat) at :2523, a 14-bit field (DC_RXSTAT_RXLEN 0x3FFF0000, if_dcreg.h:415) - subtracts ETHER_CRC_LEN at :2568 and assigns it to the freshly re-posted mbuf at :2583 (quick path, dc_quick=1 default) or copies it out via m_devget at :2590, with NO bound against the posted cluster (2040 usable bytes: MCLBYTES=2048 minus the m_adj(8) in dc_newbuf, if_dc.c:2331). The only gate (:2548-2565) reads error bits from the same device-produced word and explicitly tolerates GIANT. A device-written descriptor with RXERR clear and FRAMESZ=16383 yields m_len=16379 on a 2040-byte cluster: up to 14339 bytes of heap over-read handed to the stack (BPF taps -> userspace info leak; header walks within the claimed length). FRAMESZ<4 wraps total_len negative (m_len ~4GB unsigned) -> stack OOB walk/panic. Precondition: malicious or misbehaving dc(4) device (buggy clone silicon among the ~15 families this driver binds, attacker-controlled PCIe/Thunderbolt DMA, or platform DMA corruption) - same trust boundary as DF-3604 (bce). Guest runtime: pci/if_dc present in kernel and /boot/kernel/if_dc.ko exists, but the audit guest has only virtio hardware (ifconfig: vtnet0 lo0; pciconf: QEMU i440fx + virtio only), so the descriptor-DMA precondition cannot be produced -> inconclusive per family convention. The exact integer mechanics were executed on the guest via trigger.c (build.log/run.log): FRAMESZ=16383 -> m_len=16379 (OOB READ 14339 bytes); FRAMESZ=2 -> m_len=-2 (unsigned ~4294967294).",
  "exploit_chain": "",
  "evidence": "findings/poc/DF-3849/VERDICT.md; run.log (hardware-absence probe: ifconfig/pciconf/kldstat + trigger output); build.log (trigger built and executed on guest); fix.diff (clamp: drop frames with total_len<=0 || total_len > MCLBYTES-8, re-post cluster)",
  "kernel_refs": [
    "sys/dev/netif/dc/if_dc.c:2523",
    "sys/dev/netif/dc/if_dc.c:2548",
    "sys/dev/netif/dc/if_dc.c:2568",
    "sys/dev/netif/dc/if_dc.c:2583",
    "sys/dev/netif/dc/if_dc.c:2590",
    "sys/dev/netif/dc/if_dc.c:2321",
    "sys/dev/netif/dc/if_dc.c:2343",
    "sys/dev/netif/dc/if_dcreg.h:415",
    "sys/dev/netif/dc/if_dcreg.h:465"
  ],
  "poc_changes": "No seed PoC. Authored trigger.c (userspace arithmetic replica using the macros verbatim from if_dcreg.h) + hardware-absence probe, mirroring the DF-3604 (bce) family convention.",
  "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": 120,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o /root/trigger /root/trigger.c",
  "run_cmd": "vm.sh run_root /root/trigger; ifconfig -l; pciconf -lv | head; kldstat -v | grep -m2 if_dc",
  "code_hash": "d29d43eba0dca07b26335c617d23658f63bce9c85afbab5bf02ef9de3138ec15",
  "notes": "dc(4) instance of the DF-3604 (bce) NIC-length-trust family. Distinct from known DF-1248/DF-1249 (SROM parse OOB; pnic_rx_bug_war unbounded copy): this is the mainline dc_rxeof path, hit by every chip the driver supports, not just PNIC SROM/FIFO-bug corner cases.",
  "recommended_fix": "Clamp total_len after the CRC subtraction: drop (ierrors++, re-post cluster) frames with total_len <= 0 or total_len > MCLBYTES - sizeof(u_int64_t).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff authored against the read-only sys/ tree (git apply --check clean). Cannot be driver-level validated on this guest (no dc hardware); the clamp is a static bounds check identical in shape to the error-path handling already in dc_rxeof.",
  "fix_evidence": "findings/poc/DF-3849/fix.diff"
}