DF-4079 / verdict.json
{ "finding_id": "DF-4079", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED via the production-handler KLD dispatch rig (DF-4106/DF-4266 evidence class): the guest kernel ships `device oce`, so the rig binds the kernels OWN oce_rq_handler()/oce_alloc_rx_bufs()/ring-allocator as externs over a fabricated post-attach softc (BE3 flags, verbatim oce_rq_init DMA replay, real busdma rings, real posted clusters, MMIO BAR stand-ins) and dispatches it on firmware-shaped CQEs. Stock kernel: pkt_size=16383/num_fragments=1 delivered a 2048-byte chain claiming 16383 (14335 phantom bytes); pkt_size=16383/num_fragments=7 delivered 14336 bytes claiming 16383 (2047 phantom bytes \u2014 the max 7x2048<16383 trust-boundary gap); rx_bytes counted the phantom length. Panic mode: the cited stack offset-walker m_copydata (sys/kern/uipc_mbuf.c:1679 KASSERT, INVARIANTS kernel) panicked with backtrace m_copydata() <- df4079_input() <- oce_rx.isra.10() <- oce_rq_handler() \u2014 production oce_rx built the chain, production m_copydata died on it. Fix (residual-length drop in oce_rx) validated on a rebuilt+rebooted kernel: both crafted CQEs dropped (chains=0, violations=0, rx_pkts=0, FIX CONFIRMED) and the panic mode survives. Threat model unchanged: firmware/DMA-controlled CQE; not remotely reachable without the NIC.", "exploit_chain": "firmware/DMA-shaped RX CQE (pkt_size=16383, num_fragments=1..7) -> production oce_rq_handler/oce_rx builds a legal-RQ mbuf chain whose m_pkthdr.len exceeds its data by up to 2047 bytes -> if_input -> any offset-walking consumer (m_copydata/m_copym: forwarding, fragmentation, ICMP-error) reads past the chains real end -> KASSERT panic (demonstrated); with frame bytes also firmware-controlled, silent OOB reads of adjacent cluster data / TCP sequence desync are the same primitive short of the assert.", "evidence": "run.log (stock baseline: both CHAIN INVARIANT VIOLATION markers with per-mbuf m_len dumps); panic.txt (panic: m_copydata: offset > size of mbuf chain + backtrace oce_rx.isra.10 <- oce_rq_handler); fix_run.log (patched kernel: chains=0 violations=0 FIX CONFIRMED); fix_build.log (full 41592-line nativekernel build, BUILD_DONE_OK); panic_console_full.log (full serial console of the panic run)", "kernel_refs": [ "sys/dev/netif/oce/oce_if.c:1260", "sys/dev/netif/oce/oce_if.c:1274", "sys/dev/netif/oce/oce_if.c:1290", "sys/dev/netif/oce/oce_if.c:1291", "sys/dev/netif/oce/oce_if.c:1299", "sys/dev/netif/oce/oce_if.c:1373", "sys/dev/netif/oce/oce_if.c:1381", "sys/dev/netif/oce/oce_hw.h:2531", "sys/dev/netif/oce/oce_hw.h:2549", "sys/kern/uipc_mbuf.c:1679" ], "poc_changes": "Seed pack had no PoC (marked hardware-gated/untested). Replaced with the production-handler KLD dispatch rig: extern-binds the kernels own oce_rq_handler + posting/ring helpers, fabricates the post-attach softc (verbatim oce_rq_init DMA replay), posts real clusters via REAL oce_alloc_rx_bufs, crafts CQEs in DMA memory, dispatches the real handler; if_input shim proves pkthdr.len > sum(m_len); panic mode dispatches the real m_copydata.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64 (reproduced) / #1: Thu Oct 15 13:06:11 UTC 2026 (fix validation)", "runtime_sec": 45, "guest_dirty": 0, "build_cmd": "cd /root/df4079 && make -m /usr/src/share/mk (sh build.sh)", "run_cmd": "kldload ./df4079_oce_poc.ko; sysctl -w kern.df4079.go=1 (baseline) | sysctl -w kern.df4079.panic=1 + go=1 (panic)", "code_hash": "c50f10aeaf68bd0fb396a786e0d67c947d6806d34abc8b11d324dddcd5e686a8", "notes": "Second baseline run produced byte-identical markers (deterministic). Handler address moved 0xffffffff805c9e50 -> 0xffffffff805c9e80 after the rebuild, proving the rig dispatches the patched kernels own code. mbuf pool balanced at teardown (oce_free_posted_rxbuf real). Guest reset to stock-source snapshot afterwards.", "recommended_fix": "In oce_rx, after the fragment loop, drop the chain when residual len != 0 (pkt_size exceeded num_fragments x frag_size); never set m_pkthdr.len above the chains real data.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (residual-length drop in oce_rx) applied to guest /usr/src, kernel rebuilt via make -j6 nativekernel KERNCONF=X86_64_GENERIC (full log fix_build.log) and rebooted (#1 Thu Oct 15 13:06:11 UTC 2026); identical rig re-dispatched against the patched kernels own oce_rq_handler: both crafted CQEs dropped (chains delivered=0, violations=0, rx_pkts=0, rx_bytes=0, FIX CONFIRMED) and panic mode SURVIVES. Every defective behavior gone.", "fix_evidence": "fix_run.log (FIX CONFIRMED markers on kernel #1); fix_build.log (BUILD_DONE_OK, kernel install completed 13:11:22); panic.txt vs fix survival (no second panic.txt exists \u2014 the patched panic-mode run completed with GO_RC=0)." } |