{
  "finding_id": "DF-5271",
  "status": "reproduced",
  "reproduced": true,
  "impact": "device-directed kernel heap OOB write + OOB read (4 fully user-chosen bytes per ioctl at any offset up to ~64KB past a 32-byte kmalloc chunk, device-chosen offset via 16-bit blk_desc_len, unlimited repetitions; OOB read returns 4 heap bytes per ioctl to userland). Root-gated entry (caps_priv_check_self SYSCAP_RESTRICTEDROOT at cdopen) with attacker-controlled SCSI/USB CD-ROM hardware - same threat model as known DF-0987/DF-2268.",
  "confidence": "certain",
  "verdict": "REPRODUCED on the stock guest kernel with an evil CD-ROM CAM SIM (evilcd.ko): the device forces the 6->10-byte mode-command switch (cd6byteworkaround sets minimum_command_size=10 permanently after a rejected MODE_SENSE(6)), then returns a MODE SENSE(10) header with data_length=0 (passes the only check in cdgetmode, which validates data_length but never blk_desc_len) and a computed 16-bit blk_desc_len. cdgetpage -> find_mode_page_10 returns mode_buf+8+blk_desc_len and the audio ioctls read and write through it: CDIOCGETVOL returned foreign-chunk/stamp bytes (00 00 00 ab), CDIOCSETVOL/CDIOCSETPATCH wrote the exact user bytes into a surgically-aimed stamped probe victim (a368a469 at the computed offsets, byte-for-byte accounted: patch[2], vol[2], patch[3], vol[3]), a second neighboring chunk received 66/67, and a final CDIOCGETVOL read the written bytes back (66 67 68 69), proving persistent corruption of memory the driver does not own. No panic (silent corruption), guest stayed up. uid=0 chain not pursued past primitive characterization because the trigger requires a privileged open (root-only device node per SYSCAP_RESTRICTEDROOT); the primitive itself (repeatable 4-controlled-byte device-aimed write in a 64KB window + OOB read for aiming) is weaponizable against adjacent heap objects.",
  "exploit_chain": "evil USB/SCSI CD-ROM + (root|automount|mount) open -> device fails MODE_SENSE(6) -> cd6byteworkaround switches periph to 10-byte mode commands permanently -> device returns mode header {data_length=0, blk_desc_len=N} -> cdgetmode ENOSPC check passes (checks data_length only) -> cdgetpage/find_mode_page_10 = mode_buf+8+N -> CDIOCSETVOL writes vol[0..3] at page+9/11/13/15 and CDIOCSETPATCH patch[0..3] at page+8/10/12/14 (4 arbitrary user bytes per ioctl, repeatable) / CDIOCGETVOL discloses 4 OOB heap bytes per ioctl -> corruption of any object within +64KB of the 32-byte M_SCSICD chunk -> panic now, or object-pointer corruption for code execution with heap grooming.",
  "evidence": "run.log lines CDIOCGETVOL ... vol = 00 00 00 ab (OOB read), CDIOCSETVOL wrote {66 67 68 69}, readback: vol = 66 67 68 69 (persistent OOB write); dmesg.baseline.txt [EVILCD] probe victim 0xfffff8004f102620 ... CORRUPTED at offset 0 + bytes: a368a46904000d605c5c5c... (user bytes landed at the exact computed offsets in a live foreign heap chunk, stamp tail 04000d60 intact); VERDICT.md has the byte-for-byte attribution table.",
  "kernel_refs": [
    "sys/bus/cam/scsi/scsi_cd.c:3398",
    "sys/bus/cam/scsi/scsi_cd.c:3437-3466",
    "sys/bus/cam/scsi/scsi_cd.c:1880-1893",
    "sys/bus/cam/scsi/scsi_all.h:1418-1438",
    "sys/bus/cam/scsi/scsi_cd.c:2443-2448",
    "sys/bus/cam/scsi/scsi_cd.c:2508-2515",
    "sys/bus/cam/scsi/scsi_cd.c:2476-2481",
    "sys/bus/cam/scsi/scsi_cd.c:1986-1987",
    "sys/bus/cam/scsi/scsi_cd.c:3127-3131",
    "sys/bus/cam/scsi/scsi_cd.c:3173-3183"
  ],
  "poc_changes": "Seed sketch was never runnable: built a full fake-CD-ROM CAM SIM (evilcd.c) per the DF-5240 evilsim pattern (T_CDROM removable inquiry, READ CAPACITY, READ TOC, MODE SENSE 6/10, READ SUBCHANNEL, PREVENT/START_STOP handlers; XPT_PATH_INQ must NOT bzero the union ccb or timeout_ch is wiped -> xpt_free_ccb KKASSERT panic). Key rig additions: (1) reject MODE_SENSE(6) with CAM_REQ_INVALID to make the driver itself switch to 10-byte mode commands; (2) allocate a stamped 32-byte probe victim from INSIDE the MODE SENSE(10) handler (same thread/CPU/slab zone as the just-allocated mode_buf, delta 0x40 in the decisive run) and compute blk_desc_len = victim-mode_buf-20 so the ioctl writes land on it; (3) sysctl check_victims scans and hexdumps; (4) usched :1 pinning for LIFO chunk stability; poc_write flags added for pre-armed runs (no fork between ioctls).",
  "attempts": 6,
  "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": 1800,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df5271 && make && cc -O -o poc_write poc_write.c (see build.sh)",
  "run_cmd": "kldload ./evilcd.ko; sysctl debug.evilcd.blkdesc=0; sysctl debug.evilcd.probe=1; sysctl debug.evilcd.armed=1; usched :1 ./poc_write /dev/cd1 noarm; sysctl debug.evilcd.check_victims=1 (see run.sh)",
  "code_hash": "sha256:evilcd.c=265188e3f04e4871,poc_write.c=65ab5c9537ecf4b8",
  "notes": "Also demonstrated the 6-byte flavors OOB read feed: cd6byteworkaround reads find_mode_page_6(header6)->page_code/page_length (scsi_cd.c:3173-3183) with the same unvalidated blk_desc_len (up to +259 from the 32-byte buffer). Three earlier choreography attempts (freed-window reuse, absolute aiming, 64B target spray) failed for allocator-locality reasons (fragmented heap, zone-granular allocation) and were superseded by the in-handler probe victim, which is deterministic. dmesg on the decisive run also shows MODE_SENSE(6) failed, increasing minimum CDB size to 10 bytes.",
  "recommended_fix": "In cdgetmode(), reject mode headers whose hdr_size + blk_desc_len + sizeof(union cd_pages) exceeds alloc_len (extend the existing data_length ENOSPC check); fix.diff validated.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Single-fix kernel (fix.diff applied to guest /usr/src, make nativekernel K86_64_GENERIC + installkernel + reboot): identical PoC run returns ENOSPC from the audio ioctls (driver prints allocated mode page ... < returned length), probe victim untouched (0 corrupted chunks), no readback of previously written bytes. See fix_build.log, run.patched.log.",
  "fix_evidence": "fix_run.log / run.patched.log: CDIOCGETVOL fails ENOSPC, check_victims: probe victim untouched, 0 corrupted; guest stays up."
}