⬢ DragonFlyBSD Kernel Audit
DF-4067 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4067",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none observed (hardware-gated); source-level: kernel heap OOB read up to 63489 bytes past a 2048-byte std cluster (65535 on u16 ti_len) delivered into received frames via BPF/sockets; jumbo path up to 56513 bytes past a 9024-byte slot incl. past the contigmalloc block; page-fault panic variant",
  "confidence": "certain",
  "verdict": "Source-level certain, runtime hardware-gated (inconclusive per family convention, matching DF-3604/DF-3989/DF-4024/DF-4045/DF-4055). ti_rxeof sets the delivered mbufs length verbatim from the NIC-DMAd return-ring descriptor field ti_len (uint16_t, if_tireg.h:710) at if_ti.c:1690 (m->m_pkthdr.len = m->m_len = cur_rx->ti_len) and hands the mbuf to ifp->if_input at if_ti.c:1706 -- with NO bound against the buffer actually backing the descriptor: std ring cluster = MCLBYTES 2048 minus ETHER_ALIGN 2 = 2046 usable (if_ti.c:694-705, armed in ti_newbuf_std; firmware-legit ceiling rcb->ti_max_len = TI_FRAMELEN 1518 at if_ti.c:1279), mini ring MHLEN-2 (if_ti.c:730-741,1305), jumbo ring TI_JLEN slot 9024 minus 2 = 9022 usable (if_ti.c:799-802, rcb max 9018 at if_ti.c:1290). A descriptor claiming ti_len above the buffer capacity makes every m_len consumer (BPF tap, ether_input, protocol m_copydata/pullup, socket receive) read past the buffer: adjacent-cluster/mbuf/pool kernel heap disclosed into delivered packets (info leak to any local user with a socket on the interface) or unmapped-tail fault (panic). Worst cases: std m_len=65535 on 2048B cluster = 63489 bytes OOB (16x the cluster); jumbo 65535 on 9024B slot = 56513 bytes OOB, past the 384*9024=3.4MB contigmalloc pool for large claims. Composes with DF-4066 (same descriptor picks the buffer AND declares its length). Runtime: audit guest has zero Tigon-family PCI devices (env.txt), so the faulty-firmware trigger cannot be instantiated; trigger.c (extent model) builds and runs on the guest (run.log RC=0).",
  "exploit_chain": "On real (faulty/malicious) Tigon/Tigon2 hardware or PCIe DMA tampering: return-ring descriptor with no TI_BDFLAG_ERROR and ti_len=65535 -> driver builds an mbuf claiming 65535 bytes over a 2048-byte std cluster -> leaked kernel-heap bytes ride into received frames, readable by any local user with a receiving socket on tiX / a BPF listener, or the stack faults on an unmapped tail -> panic. Inbound-only: read primitive (plus DF-4066s write primitive on the same descriptor).",
  "evidence": "run.log (per-ring extent table, std 63489 B / jumbo 56513 B headline numbers, RC=0); build.log; env.txt (no Tigon PCI devices on guest, md5 match of audited source); VERDICT.md (path:line trace + cleared length surfaces); trigger.c; fix.diff; fix_build.log (patched module compiles -Werror clean on guest)",
  "kernel_refs": [
    "sys/dev/netif/ti/if_ti.c:1690",
    "sys/dev/netif/ti/if_ti.c:1706",
    "sys/dev/netif/ti/if_ti.c:694",
    "sys/dev/netif/ti/if_ti.c:705",
    "sys/dev/netif/ti/if_ti.c:730",
    "sys/dev/netif/ti/if_ti.c:741",
    "sys/dev/netif/ti/if_ti.c:799",
    "sys/dev/netif/ti/if_ti.c:802",
    "sys/dev/netif/ti/if_ti.c:1279",
    "sys/dev/netif/ti/if_ti.c:1290",
    "sys/dev/netif/ti/if_ti.c:1305",
    "sys/dev/netif/ti/if_tireg.h:710",
    "sys/dev/netif/ti/if_tireg.h:821",
    "sys/dev/netif/ti/if_tireg.h:822",
    "sys/dev/netif/ti/if_tireg.h:1048",
    "sys/sys/param.h:497"
  ],
  "poc_changes": "No seed PoC (no prior findings on this file). Authored trigger.c (per-ring extent model) per the DF-4024 convention; honest hardware-absent verification.",
  "attempts": 3,
  "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/df4067 /tmp/df4067.c",
  "run_cmd": "vm.sh run_root /tmp/df4067; echo RC=$?",
  "code_hash": "b886450cc6ca0dd2ffb35fe780692e9379c45a79dce3d070a449e0813267b215",
  "notes": "Pass-2 checklist item (a) for if_ti.c (DF-3604/3761/3715/3989/4024/4045/4055 family application). MHLEN modeled with a conservative 224 lower bound (exact value boot-dependent); the OOB conclusion is independent of the exact MHLEN since ti_len is 16-bit. Cleared: TX direction writes device lengths from kernel mbufs (no device input); ti_newbuf_* descriptor/buffer pairs consistent.",
  "recommended_fix": "Bound cur_rx->ti_len by the rings buffer capacity (MCLBYTES-2 / MHLEN-2 / TI_JUMBO_FRAMELEN-2) in ti_rxeof; drop over-length frames (ierror + m_freem), see fix.diff.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff adds a per-ring maxlen and drops over-length frames using the drivers existing error-drop idiom; git apply --check passes and the patched if_ti.ko builds clean on the guest with -Werror -std=gnu11 (fix_build.log FIXBUILD_f2_RC=0); runtime validation impossible without Tigon hardware.",
  "fix_evidence": "findings/poc/DF-4067/fix.diff + findings/poc/DF-4067/fix_build.log"
}