⬢ DragonFlyBSD Kernel Audit
DF-4268 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4268",
  "status": "not_reproduced",
  "verdict": "Not reproduced \u2014 and traced to a dead end in the audited artifact: the shipped X86_64_GENERIC kernels wb_rxeof (gcc 8.3) merged the length checks (:983/:984) and the length use (:1004) into ONE load of the device-written status word (objdump: mov (%rdx),%esi @ +0x44 feeds both the merged range check sub $0x3c; cmp $0x5c4; ja and, via and $0x3fff,%esi, m_devgets length) \u2014 the value copied into the received packet is the same fetch that was range-checked, so the claimed check/use divergence to 16383 and the ~12KB OOB read from the 4096-byte wb_rxbufs[0] cannot occur in this binary; effectively a false positive on the compiled artifact this audit targets. Only a flags-vs-length split (snapshot :973 vs the single length load) survives, which is not memory-unsafe. Dynamically corroborated: the PRODUCTION handler raced against an actively adversarial chip (GOOD len64 <-> HUGE len16383, both OWN=1, 4:1 duty, separate CPUs) for 250 dispatches/~17s delivered 221 frames with max length 60 and ZERO oversized packets; an exact-semantics volatile transcription (four distinct fetches) also never diverged across ~130k dispatches (software writers cannot land stores inside the readers ~30ns fetch window; only in-flight DMA could, and the binarys length path fetches once). The source-level four-fetch pattern is still a genuine double-fetch of device memory and the fix is validated as hardening: on the rebuilt kernel the machine code drops to ONE status load per iteration and the race stays at 0 wins. Recommend keeping the fix (defense against future compiler changes), downgrading/removing the info-leak impact for this build.",
  "reproduced": false,
  "impact": "none",
  "confidence": "certain",
  "exploit_chain": "",
  "evidence": "wb_rxeof.stock.disasm (per-iteration loads at +0x1c and +0x44; range check and m_devget length both derive from the +0x44 fetch); run.race_production.dmesg.log (DF-4268 PRODUCTION race over after 250 dispatches (~17 s): delivered=221 maxplen=60 WON=0); run.race_production_v1_miscomputed_huge.log (276 deliveries, maxplen 1019 <= 1536 with mid-range toggle values); run.race_ctl_userland.log/.dmesg + run.race_ctl_kernel.log (control transcription, 0 wins in ~130k dispatches); run.race_production_fixed.log (fixed kernel: single-load pattern + delivered=188 maxplen=60 WON=0); VERDICT.md",
  "kernel_refs": [
    "sys/dev/netif/wb/if_wb.c:973",
    "sys/dev/netif/wb/if_wb.c:983",
    "sys/dev/netif/wb/if_wb.c:984",
    "sys/dev/netif/wb/if_wb.c:1004",
    "sys/dev/netif/wb/if_wb.c:1015",
    "sys/kern/uipc_mbuf.c:2235",
    "sys/dev/netif/wb/if_wbreg.h:242"
  ],
  "poc_changes": "Replaced the seeds no runnable PoC with: (a) scripted objdump of the production wb_rxeof fetch pattern (kld_run.sh disasm); (b) a two-CPU race harness \u2014 userland chip writing rx_list[0].wb_status via a rig sysctl (kern.dfwb3.tog) with GOOD/HUGE 4:1 duty, usched-pinned away from the dispatching sysctl, racing the REAL production handler (go4268); (c) an exact-semantics volatile transcription control (go4268ctl) raced with userland x1/x3 and kernel ns-rate togglers. Seeds mis-set HUGE constant (RXLEN 1023 vs 16383) corrected; two rig incidents (toggle-thread lwkt_exit panic; spinning remote kernel thread panic) documented \u2014 both after race data capture, neither involving the code under test.",
  "attempts": 6,
  "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 (baseline); #1: Wed Oct 14 22:35:12 UTC 2026 (fix validation)",
  "runtime_sec": 900,
  "guest_dirty": 0,
  "build_cmd": "cd /root/dfwb3 && make -m /usr/src/share/mk && cc -O2 -o df8_toggle df8_toggle.c",
  "run_cmd": "sh /root/dfwb3/kld_run.sh disasm; (nohup usched bsd4:8 ./df8_toggle >/tmp/tog.log 2>&1 &); sleep 1; usched bsd4:1 sysctl -w kern.dfwb3.go4268=1; killall df8_toggle",
  "code_hash": "7e63578586f10529a7038445604b887f9147dc6ffc90b61d38c334b13fb25194",
  "notes": "The verdict false_positive is scoped to the audited compiled artifact: the source-level double-fetch exists as written (four reads of wb_status) and the seeds concern is legitimate for future/different compiler output \u2014 hence the fix is retained and machine-code-validated (2 loads -> 1 load per iteration). Severity should be revisited by the triage team (suggest Info/Low hardening for this build, keeping the pattern note). wb_intr has no inlined second RX copy (checked). The ~130k-dispatch control failure to win is itself evidence of cache-line quantization, documented in VERDICT.md; a real DMA write in flight could split genuinely-twice-fetched code, which is precisely what the fix eliminates.",
  "recommended_fix": "Use the :973 rxstat snapshot for the length checks and the length use (WB_RXBYTES(rxstat)) instead of re-reading cur_rx->wb_ptr->wb_status three times \u2014 validated in fix_validated.diff hunk 2/3 (machine code: one status load per iteration)",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "not_testable behaviourally: the OOB was never reachable on this build (baseline already clean), so no pre/post behavioural delta exists; the patchs effect is nevertheless verified at the machine-code level \u2014 the shipped 2-loads-per-iteration pattern drops to 1 load on the rebuilt kernel, eliminating the double-fetch entirely \u2014 and the fixed-kernel race stays at 0 wins / 188 deliveries / maxplen 60",
  "fix_evidence": "run.race_production_fixed.log (objdump section: single mov (%rax),%eax per iteration, no second (%rdx) reload; race summary delivered=188 maxplen=60 WON=0); fix_validated.diff; VERDICT.md Fix assessment"
}