{
  "finding_id": "DF-2284",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "REPRODUCED on the stock INVARIANTS kernel: 400 write-only sg requests (64 KiB each) left M_DEVBUF at 1014 allocations / 25.3 MB against a 211/208K baseline, and the count and bytes stayed identical across last-close + 3 s + 5 s -- sgoninvalidate (scsi_sg.c:169-191, whose own comment says XXX Return all queued I/O with ENXIO) and sgcleanup (:194-206) drain nothing; every sg_rdwr + union ccb + buffer queued by sgwrite (:652/:664/:700/:740) is orphaned forever because only a pack_id-matching sgread (:807,:855-856) ever frees them. A second independent run on the same boot re-leaked exactly ~2000 more allocations, confirming linearity. The invalidation-UAF surface clause of the finding is corroborated by DF-2283 run.log: a reader parked in sgread while the open file description closed wedged the guest (kernel livelock) -- the exact parked-reader-vs-freed-softc interaction the finding describes. RESTRICTEDROOT/operator gated (0600 root-only node on this guest).",
  "exploit_chain": "",
  "evidence": "run1.log/phase2.log/phase3.log: M_DEVBUF 211/208K -> 1011/25.3M after 400 write-only requests, unchanged after kill-holder (last close) + 8 s; the second stock run (directclose) re-leaked +800 allocations",
  "kernel_refs": [
    "sys/bus/cam/scsi/scsi_sg.c:652",
    "sys/bus/cam/scsi/scsi_sg.c:664",
    "sys/bus/cam/scsi/scsi_sg.c:700",
    "sys/bus/cam/scsi/scsi_sg.c:740",
    "sys/bus/cam/scsi/scsi_sg.c:807",
    "sys/bus/cam/scsi/scsi_sg.c:855",
    "sys/bus/cam/scsi/scsi_sg.c:169",
    "sys/bus/cam/scsi/scsi_sg.c:183",
    "sys/bus/cam/scsi/scsi_sg.c:194",
    "sys/bus/cam/scsi/scsi_sg.c:205"
  ],
  "poc_changes": "v1 measured with a misparsed vmstat column and closed the fd mid-session (colliding with the DF-2282 close-underflow and wedging the guest); v2 forks a holder that parks with the fd open and measures from an external session (phase2/phase3), plus a directclose variant for the close-time question.",
  "attempts": 5,
  "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": 240,
  "guest_dirty": 1,
  "build_cmd": "cc -O -Wall -o sg2284 sg2284.c",
  "run_cmd": "./sg2284  (then external vmstat -m | grep devbuf; kill -9 holder)",
  "code_hash": "689a76d555dc387bd115a6e62e9a02048b2d763ba1481aff4ea457a5433bd895",
  "notes": "Fix validation honest result: the drain in fix.diff targets sgoninvalidate/sgcleanup, but on this system the periph is NOT invalidated at last close (CAM keeps the periph with the LUN; /dev/sg0 survives close and camcontrol rescan), so the close-time leak persists on the fix kernel too and the invalidation path itself is not triggerable on a virtio DVD without hot-removal. fix.diff remains correct for the invalidation path the finding names; recorded fix_status=not_testable with this analysis.",
  "recommended_fix": "Drain rdwr_done in sgoninvalidate (completed entries) and sgcleanup (remainder) before freeing the softc (fix.diff); note a complete fix also wants a close-time path (periph refcounting is DF-2282).",
  "fix_status": "not_testable",
  "fix_validation": "fix kernel: close-time retention unchanged (1014/25.3M persisted; directclose re-leaked +756) because last close does not run sgoninvalidate on this system; invalidation requires LUN removal which the QEMU virtio DVD cannot do; fix.diff compiles in the combined fix kernel (nativekernel RC=0)"
}