DF-2421 / verdict.json
{ "finding_id": "DF-2421", "status": "reproduced", "verdict": "REPRODUCED on live AHCI hardware: an operator-privileged XPT_SCSI_IO submitted via /dev/pass0 with CAM_DIR_NONE carries a raw user-supplied csio->data_ptr into ahci_xpt_scsi_disk_io (passsendccb skips cam_periph_mapmem for DIR_NONE, scsi_pass.c:565-568; cam_periph.c:677 returns untouched), where the synthetic handlers write it unconditionally. Surgical non-fatal proof: single INQUIRY CCBs zeroed+overwrote kernel bss hostname[] and .data version[] at byte-exact chosen offsets, each read back via sysctl (kern.hostname truncated from 64 to exactly 8/16/40 chars; kern.version cut at +64), CCBs returning CAM_REQ_CMP silently; READ_CAPACITY (:1159) and EVPD page_inquiry (:1693) paths proven the same way. Panic proofs: data_ptr=NULL -> Fatal trap 12 fault VA 0x0 supervisor WRITE Stopped at memset+0x2b (= bzero(rdata,rdata_len)); data_ptr=0xfffff800deadf000 -> trap 0xc at the same write instruction, kernel panics faulting the caller-chosen address. uid=0 escalation not completed: primitive is write-only with constrained content (zeros + inquiry header + IDENTIFY-derived strings), no kernel-read oracle from the same interface to locate dynamic targets; the arbitrary-address write itself (where+length fully controlled) is demonstrated against live kernel .data/.bss.", "reproduced": true, "impact": "panic", "confidence": "certain", "exploit_chain": "operator/root opens /dev/passN (0600 root:operator) -> CAMIOCOMMAND XPT_SCSI_IO, CAM_DIR_NONE, data_ptr=<kernel VA>, dxfer_len=<len>, INQUIRY/READ_CAPACITY/EVPD -> passsendccb skips mapmem -> ahci_xpt_scsi_disk_io bzero/bcopy at the raw pointer -> silent arbitrary kernel-address write (demonstrated on hostname[]/version[]) or panic (NULL / unmapped VA)", "evidence": "run.log (verbatim: hostname 64->8/16/40 chars, version truncated at +64, all CAM_REQ_CMP), panic-null.txt (fault 0x0, memset+0x2b), panic-addr.txt (chosen VA fault), fix-validation.log (patched kernel: all 5 attack modes -> CAM_REQ_INVALID 0x6, zero corruption, normal I/O unaffected)", "kernel_refs": [ "sys/dev/disk/ahci/ahci_cam.c:1083", "sys/dev/disk/ahci/ahci_cam.c:1109", "sys/dev/disk/ahci/ahci_cam.c:1159", "sys/dev/disk/ahci/ahci_cam.c:1693", "sys/bus/cam/scsi/scsi_pass.c:565", "sys/bus/cam/cam_periph.c:677", "sys/bus/cam/cam_xpt.c:3888" ], "poc_changes": "no runnable PoC existed; wrote ahcipoc.c (modes inquiry-null / inquiry-addr / readcap-addr / evpd-addr / surgical / read10 / atapi), built against the guests /usr/src CAM headers (/usr/include/cam is not installed); required live AHCI hardware attached at QEMU launch (up_ahci.sh)", "attempts": 7, "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": 900, "guest_dirty": 0, "build_cmd": "guest: cc -O -I/usr/src/sys -I/usr/src/sys/bus -o ahcipoc ahcipoc.c", "run_cmd": "./ahcipoc surgical <kernva-hex> 36 (and inquiry-null / inquiry-addr fffff800deadf000)", "code_hash": "56eeebd163c12d51818b8c5018719e4e47e5ea7e6182095769c23210ec80b9bb", "notes": "content control: zeros + fixed INQUIRY/READ_CAPACITY header fields + IDENTIFY-derived vendor/product/serial strings (serial/model operator-chosen on emulated media). Symbol addresses from /boot/kernel/kernel symtab (no KASLR). Fix kernel #1 Thu Oct 15 02:34:42 UTC 2026.", "recommended_fix": "reject CAM_DIR_NONE CCBs with dxfer_len > 0 in ahci_xpt_scsi_disk_io() and ahci_xpt_scsi_atapi_io() before any data_ptr dereference (fix.diff, validated: CAM_REQ_INVALID)", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fixed", "fix_evidence": "fix-validation.log: patched kernel, all five attack modes return cam_status 0x6 (CAM_REQ_INVALID), hostname/version unchanged, read10/dd normal (260-720 MB/s)" } |