{
  "finding_id": "DF-4837",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "REPRODUCED (logic/bounce-accounting harness; guest has no IDA controller \u2014 DF-4559 methodology). ida_construct_qcb() clears qcb->flags=0 (ida.c:391) and never sets DMA direction for bios, so the :399-401 pre-sync is always BUS_DMASYNC_PREWRITE and ida_done()s :506 gate (flags & DMA_DATA_TRANSFER == 0) skips BOTH the POSTREAD sync and bus_dmamap_unload for every disk I/O. On >4GB machines the buffer tag bounces (parent 32-bit clamp, busdma_machdep.c:272; ida_pci.c:260-265): POSTREAD is where bounce->orig copyback happens (busdma_machdep.c:1054-1063) so every bounced READ completes B_OK with the buffers STALE contents (silent disk data corruption for the FS layer), and every load leaks its bounce page (add_bounce_page appends; only unload returns them) \u2014 unbounded kernel memory growth with I/O. On <=4GB boxes the tag never bounces and the bug is latent. Harness with faithful map/zone bookkeeping driven by the verbatim flag logic: baseline 1 READ -> STALE buffer + 1 page held; 64 READs -> 64 pages held; fixed model (per-direction flags) delivers device data and holds 0 pages.",
  "exploit_chain": "no privilege chain \u2014 integrity/availability bug: >4GB host + 32-bit Compaq SMART/IDA card -> ordinary disk I/O -> bounced READs silently return stale page contents (filesystem-level data corruption) + one leaked bounce page per I/O (unbounded kernel memory leak, eventual stall)",
  "evidence": "run.log: BASELINE: after 1 READ bios: caller buffer STALE (device data LOST); bounce pages allocated=1 still held=1 (leaked=1); BASELINE: after 64 READ bios: ... allocated=64 still held=64 (leaked=64); FIXED : after 64 READ bios: caller buffer has device data; bounce pages allocated=1 still held=0 (leaked=0). VERDICT.md has the full path:line trace incl. the busdma clamp and POSTREAD copyback.",
  "kernel_refs": [
    "sys/dev/raid/ida/ida.c:391",
    "sys/dev/raid/ida/ida.c:399",
    "sys/dev/raid/ida/ida.c:506",
    "sys/dev/raid/ida/ida.c:512",
    "sys/dev/raid/ida/ida_pci.c:260",
    "sys/platform/pc64/x86_64/busdma_machdep.c:272",
    "sys/platform/pc64/x86_64/busdma_machdep.c:1054"
  ],
  "poc_changes": "No seed PoC (pass-2 new finding). Harness models DFly busdma bounce bookkeeping (per-load page reservation, PREWRITE orig->bounce, POSTREAD bounce->orig, unload returns pages) and drives it with the exact flag logic of ida_construct_qcb()/ida_done(), baseline vs fixed arms.",
  "attempts": 1,
  "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": 30,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o df4837 df4837_harness.c",
  "run_cmd": "./df4837",
  "code_hash": "fe80567019fb7e25eef7b8f9c205e8623d372e930634f4e0049bdb88950ea504",
  "notes": "Guest itself has <4GB visible to the tag (hw.physmem=4257873920, right at the boundary) and no IDA card, so an end-to-end runtime trigger is impossible \u2014 harness verification per DF-4559 precedent. The same flags bug also makes the pre-sync direction stale in ida_command() (:339 reads flags set only at :350); fix.diff moves that assignment before the sync as well.",
  "recommended_fix": "Set qcb->flags = DMA_DATA_TRANSFER | (read ? DMA_DATA_IN : DMA_DATA_OUT) in ida_construct_qcb() and assign qcb->flags in ida_command() before the pre-sync (fix.diff in pack)",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Validated with the harness fixed-model arms: with per-direction flags, ida_done performs the POSTREAD copyback and the unload \u2014 buffer receives device data and 0 bounce pages remain held after 1 and 64 READs; baseline loses data and leaks one page per I/O. fix.diff not applied to the read-only sys/ tree; kernel-build validation not meaningful without an IDA controller in the guest.",
  "fix_evidence": "run.log FIXED lines: FIXED : after 1 READ bios: caller buffer has device data ... (leaked=0) and same for 64; fix.diff in pack."
}