DF-4024 / verdict.json
{ "finding_id": "DF-4024", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-level certain, runtime hardware-gated (inconclusive per family convention). re_rxeof takes the received frame length from the NIC-DMAd descriptor 14-bit GFRAGLEN (RE_RXBYTES at if_re.c:1142 = cmdstat & 0x3FFF, if_revar.h:54 / if_rereg.h:139) and applies it with NO bound: (1) single-fragment EOF if_re.c:1228-1229 sets m->m_pkthdr.len = m->m_len = total_len - 4 on an MCLBYTES (2048) cluster from re_newbuf_std (:964-975) -- a descriptor claiming 16383 yields m_len 16379, so every consumer trusting m_len (ether_inputs ETHER_BPF_MTAP, mtod/m_copydata pulls past 2KB) reads up to 14331 bytes of ADJACENT KERNEL HEAP into delivered packet payloads (info leak to sockets/BPF) or faults; (2) multi-fragment EOF :1209/:1226 sets m_pkthdr.len = total_len-4 possibly EXCEEDING the accumulated chain (k*2048 + last-frag bytes) so m_copydata walks m_next past NULL -> KASSERT panic (INVARIANTS) or NULL->m_len page fault (GENERIC; sys/kern/uipc_mbuf.c m_copydata, KASSERTs compiled out); (3) total_len<4 sub-case is SAFE (negative m_len dropped by ether_inputs m_len < ETHER_HDR_LEN guard, if_ethersubr.c) -- mirroring ales m_devget tot<=0. The error-summary filter (:1187) is itself device-fed and bounds nothing. Legit frames are capped by RE_RxMaxSize = re_rxbuf_size (MCLBYTES, if_re.c:850; re.c:1103-1105 programs MTU+22=1522), so any total_len>2048 single-desc or beyond-chain total is a device lie. The jumbo path is DEAD (RE_JUMBO undefined tree-wide; RE_C_CONTIGRX/RE_F_USE_JPOOL never set) so DF-1336 stays latent while this length-trust bug is live on the default driver. Runtime: guest has virtio-net only, zero Realtek devices, no hw.re sysctl (env.txt); trigger.c (geometry model) builds and runs on the guest (run.log RC=0: 14331-byte single-frag extent + chain-walk table). re(4) instance of the DF-3604(bce)/DF-3759(alc)/DF-3933(age)/DF-3989(ale) family; pass 1 filed only DF-1336 against this file.", "exploit_chain": "On real (faulty/malicious) RTL8169SC/8168/8101E/8125 hardware: DMA a completion descriptor with EOF, no error bits, GFRAGLEN=16383 -> driver builds an mbuf claiming 16379 bytes over a 2048-byte cluster -> leaked kernel-heap bytes ride into received packet payloads (readable by any local user with a socket on reX) or the stack faults -> panic. Inbound-only: no write primitive.", "evidence": "run.log (model output: 16379-2048=14331-byte OOB extent, chain-walk table, RC=0); build.log; env.txt (virtio-net only, md5 match); VERDICT.md (path:line trace); trigger.c; fix.diff (total_len bound vs re_rxbuf_size + tracked chain length)", "kernel_refs": [ "sys/dev/netif/re/if_re.c:1142", "sys/dev/netif/re/if_re.c:1187", "sys/dev/netif/re/if_re.c:1209", "sys/dev/netif/re/if_re.c:1226", "sys/dev/netif/re/if_re.c:1228", "sys/dev/netif/re/if_re.c:964", "sys/dev/netif/re/if_re.c:975", "sys/dev/netif/re/if_re.c:850", "sys/dev/netif/re/if_revar.h:54", "sys/dev/netif/re/if_rereg.h:139", "sys/net/if_ethersubr.c:1502", "sys/kern/uipc_mbuf.c:1671" ], "poc_changes": "No seed PoC (only known finding was DF-1336). Authored trigger.c as hardware-precondition + cluster-geometry model per the DF-3989 convention; honest hardware-absent verification.", "attempts": 2, "guest_uname": "DragonFly dfbsd 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": 40, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -Wextra -o /tmp/tr4024 /tmp/tr4024.c", "run_cmd": "vm.sh run_root /tmp/tr4024; echo RC_4024=$?", "code_hash": "255cd7b43bf01f325b50c38b773495d3f88dcebc6f74f8bac8b091e44718ba37", "notes": "Pass-2 checklist item (a) for if_re.c. Checked and cleared this pass: re_encap TX ring walk (maxsegs = min(tx_free, RE_MAXSEGS=16), EOR bookkeeping, dmamap swap -- bounded); re_tx_collect loop bounded by tx_free monotonics; re_rxeof descriptor walk always re-arms (re_newbufs back: label) so no ring livelock; RXERRSUM/DROP_RXFRAG chain teardown consistent; total_len<4 negative m_len SAFE via ether_input guard; sysctl handlers take the serializer correctly; ioctl privilege checks centralized in ifioctl; MSI/MSI-X alloc standard (pci_alloc_1intr); ASPM/PCIe config pokes bounded; WOL/phy paths live in re.c (other file).", "recommended_fix": "In re_rxeof drop the frame (ierrors + re_free_rxchain + re_setup_rxdesc) when total_len < ETHER_HDR_LEN+ETHER_CRC_LEN or total_len > sc->re_rxbuf_size + accumulated chain bytes (new sc->re_rxchain_len), see fix.diff.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff uses the drivers own error-drop idiom on the already-compiled path and applies clean (git apply --check); cannot be runtime-validated without re(4) hardware.", "fix_evidence": "findings/poc/DF-4024/fix.diff" } |