⬢ DragonFlyBSD Kernel Audit
DF-4024 / verdict.json
← back to finding ↓ download raw
{
  "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"
}