โฌข DragonFlyBSD Kernel Audit
DF-2859 / verdict.json
โ† back to finding โ†“ download raw
{
  "finding_id": "DF-2859",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "none",
  "confidence": "certain",
  "verdict": "sglist_split()'s trim bcopy (sys/kern/subr_sglist.c:571-574) moves `count` entries instead of the surviving `original->sg_nseg` entries, deterministically corrupting the survivor list (duplicated segments, dropped tail โ€” wrong DMA ranges for any consumer) and heap-overreading up to (2*count - sg_maxseg)*16 bytes past the kmalloc'd segs array when survivors < count. Reproduced 3/3 on the stock guest via a KLD library harness (cases A/B); OOB-read mode by construction (case C). sglist_split has zero callers in the DragonFly tree, so the realistic impact ceiling today is none (severity Low, dead code, same framing as DF-0096); the identical bug is still present in FreeBSD HEAD. One-line fix validated by in-guest kernel rebuild: baseline BUG REPRODUCED -> patched PASS.",
  "exploit_chain": "N/A โ€” dead code (no in-tree caller of sglist_split). If a consumer is ever added: split a list so survivors != count -> survivor sglist contains stale/duplicated (paddr,len) pairs -> device DMAs wrong physical memory (read of unrelated physical pages into the transfer buffer / write of transfer data to unrelated physical pages) plus heap OOB read in over-copy mode.",
  "evidence": [
    "run.log: 'A.orig.after seg[0..1] paddr=0x130000' duplicated, 'verdict: BUG REPRODUCED' (baseline run 1)",
    "run.2.log / run.3.log: same corruption on runs 2 and 3 (deterministic)",
    "fix_run.log: patched kernel -> A.orig.after = P1..P5 distinct, B.orig.after = [0x130800/0x800, P2..P5], 'verdict: PASS'",
    "fix_build.log: full nativekernel build log ending BUILD_OK (kernel #1 Wed Sep 2 13:15:59 UTC 2026)",
    "VERDICT.md: full narrative incl. dead-code reachability analysis and upstream parity check"
  ],
  "kernel_refs": [
    "sys/kern/subr_sglist.c:571",
    "sys/kern/subr_sglist.c:573",
    "sys/kern/subr_sglist.c:563",
    "sys/kern/subr_sglist.c:206",
    "sys/sys/sglist.h:105"
  ],
  "poc_changes": "no seed existed; KLD harness authored from scratch (runs at MOD_LOAD via exported sglist_alloc/append_phys/split symbols; three deterministic cases A/B/C)",
  "attempts": 3,
  "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": 640,
  "guest_dirty": 0,
  "build_cmd": "cd /root/sgdemo && make",
  "run_cmd": "kldload /root/sgdemo/sgsplit_demo.ko; sleep 1; dmesg | grep DF2859; kldunload sgsplit_demo",
  "code_hash": "4834dc2ff2ded1ffc3efda4f6ea2d0548649da4cc6b054f8305f3cecc63bebcb",
  "notes": "Dead code: sglist_split has no callers in the DF tree; severity Low per DF-0096 precedent. Upstream FreeBSD HEAD (checked 2026-09-02) has the identical `count *` trim block. Live sglist surface in DF = virtio append/alloc/free family only. Phase V for DF-2860/DF-2861 skipped: Low/Info dead-code hardening findings per contract.",
  "recommended_fix": "sglist_split: bcopy the surviving remainder โ€” `original->sg_nseg * sizeof(struct sglist_seg)` โ€” instead of `count *` (see fix.diff)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Wed Sep  2 13:15:59 UTC 2026  root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Applied fix.diff in guest /usr/src, make -j6 -DNO_CLEAN nativekernel + installkernel (fix_build.log, BUILD_OK), rebooted into kernel #1, re-ran the byte-identical sgsplit_demo.ko: all cases PASS, verdict line PASS, previously-observed duplicated/dropped segments GONE.",
  "fix_evidence": "fix_run.log (patched PASS output incl. correct [P1..P5] and [0x130800/0x800, P2..P5] survivor lists); fix_build.log (full build log, BUILD_OK)"
}