DF-3777 / verdict.json
{ "finding_id": "DF-3777", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-level certain and demonstrated on the guest kernel by a verbatim-loop replica (jme_callout_replica.ko: sysctl kern.jmereplica.rxspin=1 -> iterations=200000000 reposts=0 rx_cons 0 -> 0, i.e. the 200M-iteration guard was the ONLY thing that ended the walk; zero reposts; consumer unchanged -> descriptor provably never re-armed, loop provably unbounded). jme-specific runtime hardware-gated: the guest has no JMicron NIC, and the trigger additionally requires a faulty/malicious controller (compliant silicon always reports nsegs>=1; error frames carry JME_RX_ERR_STAT and are discarded at :2348) -> inconclusive per family convention. Root cause: the sole validation of the DMAd RX descriptor, nsegs != howmany(pktlen, MCLBYTES) (if_jme.c:2513), admits the pair (nsegs=0, pktlen=0) because howmany(0,2048)==0; jme_rxpkt (:2304-2486) with nsegs==0 executes neither the jme_newbuf repost loop (:2361) nor jme_discard_rxbufs (:2350) and advances jme_rx_cons by 0 (:2484), so jme_rxeofs unbounded for(;;) (:2494, count=-1 from jme_msix_rx :3845 / jme_rx_intr :3500 / jme_rx_restart :3882) re-reads the same OWN-clear VALID-set descriptor forever: RX interrupt thread spins holding the ring serializer, RX halts, CPU softlock. Positive pass-2 note: the :2513 cross-check CLOSES the DF-3604/3639/3663/3679/3713/3759 heap-OOB-read family for jme (pktlen bound to nsegs<=32 posted 2048-byte clusters; chain trim :2403-2413 keeps m_len in-cluster), and the pktlen<10 negative-m_len edge is dropped benignly by ether_input (if_ethersubr.c:1501).", "exploit_chain": "", "evidence": "run.log: jmereplica[rxspin]: guard=-1 iterations=200000000 reposts=0 rx_cons 0 -> 0 (unchanged == descriptor never re-armed: loop provably unbounded) and the fix-shape control jmereplica[rxspin_fix]: iterations=2 reposts=1 rx_cons 0 -> 1 (terminates; degenerate desc reposted); jme_callout_replica.c repl_rxeof_spin()/repl_rxpkt() are the verbatim if_jme.c:2494-2562/:2304-2486 loop logic against a simulated ring; fix_build.log: nativekernel RC=0 with fixes applied.", "kernel_refs": [ "sys/dev/netif/jme/if_jme.c:2494", "sys/dev/netif/jme/if_jme.c:2500", "sys/dev/netif/jme/if_jme.c:2511", "sys/dev/netif/jme/if_jme.c:2513", "sys/dev/netif/jme/if_jme.c:2350", "sys/dev/netif/jme/if_jme.c:2361", "sys/dev/netif/jme/if_jme.c:2484", "sys/dev/netif/jme/if_jme.c:3845", "sys/dev/netif/jme/if_jme.c:3500", "sys/dev/netif/jme/if_jmereg.h:985", "sys/dev/netif/jme/if_jmereg.h:995", "sys/net/if_ethersubr.c:1501" ], "poc_changes": "n/a (source-level finding; verbatim-loop replica written for this pack, sharing the module with DF-3776)", "attempts": 2, "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": 90, "guest_dirty": 0, "build_cmd": "cd /root/kmod && make (jme_callout_replica.ko, -Werror clean)", "run_cmd": "kldload /root/kmod/jme_callout_replica.ko; sysctl kern.jmereplica.rxspin=1; sysctl kern.jmereplica.rxspin_fix=1; dmesg | grep rxspin | tail -2", "code_hash": "f7952c76d117973c733b4f7867d170a34114040850e256e6f1b6e33d079e5124", "notes": "No JMicron hardware on the guest; driver compiled into running kernel. Faulty/malicious-controller threat model (same as DF-3604 family). fix_status: not_testable (behavior hardware-gated); fix mechanism demonstrated by the rxspin_fix replica control (terminates, reposts 1); fix compile validated (fix_build.log RC=0, 0 warnings).", "recommended_fix": "jme_rxeof: reject nsegs < 1 before the howmany() check - repost the single degenerate descriptor (jme_discard_rxbufs(...,1)), advance jme_rx_cons (JME_DESC_INC), continue (see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (git-apply clean) adds an explicit nsegs < 1 rejection that reposts the degenerate descriptor and advances past it before the howmany() consistency check. Mechanism validated live: replica control with the fixed shape terminates in 2 iterations with 1 repost and rx_cons advanced (vs 200M+ iterations / 0 reposts / unchanged consumer in the shipped shape). Compile validated: nativekernel build with all three jme fixes applied -> RC=0, zero warnings (fix_build.log). Driver-level runtime validation impossible without faulty JMicron hardware.", "fix_evidence": "run.log: jmereplica[rxspin_fix]: iterations=2 reposts=1 rx_cons 0 -> 1 (terminates; degenerate desc reposted); fix_build.log: >>> Kernel build for X86_64_GENERIC completed RC=0, grep -cE error:|warning: == 0." } |