DF-2420 / verdict.json
{ "finding_id": "DF-2420", "status": "reproduced", "verdict": "REPRODUCED on live AHCI hardware via the unmodified production path: with the per-port ccb free list drained on the real ahci0 port (rig uses only the drivers exported ahci_ata_get_xfer/put_xfer symbols), a single ordinary pass(4) XPT_SCSI_IO READ_10 CCB panics the kernel at ahci_xpt_scsi_disk_io+0x8f9 movl $0x1,0x60(%r12) (fault VA 0x60, supervisor WRITE = xa->flags = ATA_F_READ with xa==NULL, ahci_cam.c:1334), and an ATAPI CCB on drained port 1 panics at ahci_xpt_action+0x2d6 (inlined ahci_xpt_scsi_atapi_io, fis=xa->fis, fault VA 0x0). Live-churn negative control: 48 concurrent full-disk reads + 19639 pass CCBs survive clean because QEMUs disk advertises ncqdepth 32 == sc_ncmds (the probe prune loop ahci_cam.c:386-392 removes no slots), pinning the natural precondition to real disks with ncqdepth < ncmds, exactly as the finding states. Fix (NULL checks -> CAM_RESRC_UNAVAIL) validated on a rebuilt kernel: same drain triggers return cleanly, no panic, normal I/O restored after release.", "reproduced": true, "impact": "panic", "confidence": "certain", "exploit_chain": "", "evidence": "run.log (verbatim sessions), panic-disk.txt (Stopped at ahci_xpt_scsi_disk_io+0x8f9, fault 0x60 write), panic-atapi.txt (ahci_xpt_action+0x2d6, fault 0x0 read), flood2.log (negative control, tags=32/32), df2420_rig.c (live-state rig, no driver logic), fix-validation.log (patched kernel #1 survives all triggers with CAM_RESRC_UNAVAIL)", "kernel_refs": [ "sys/dev/disk/ahci/ahci.c:3670", "sys/dev/disk/ahci/ahci_cam.c:1082", "sys/dev/disk/ahci/ahci_cam.c:1334", "sys/dev/disk/ahci/ahci_cam.c:1524", "sys/dev/disk/ahci/ahci_cam.c:386", "sys/dev/disk/ahci/ahci_cam.c:112" ], "poc_changes": "original finding had no runnable PoC; built (1) ahcipoc.c userland pass(4) CAMIOCOMMAND trigger (built against guest /usr/src CAM headers), (2) df2420rig.ko live-state rig that drains the real free list via the exported symbols and devclass_find(\"ahci\"), (3) attached real AHCI hardware to the guest at QEMU launch (up_ahci.sh) - QEMUs AHCI bus rejects drive hotplug, and the earlier boot-hang noted in DF-4203s first round was an invocation artifact solved by explicit bootindex ordering", "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": 1500, "guest_dirty": 0, "build_cmd": "guest: cd /root/rig && make (sys/conf/kmod.mk, SYSDIR=/usr/src/sys; plus cc -O -I/usr/src/sys -I/usr/src/sys/bus -o /root/ahcipoc ahcipoc.c)", "run_cmd": "sysctl dev.df2420rig=\"hold 0\"; /root/ahcipoc read10 | sysctl dev.df2420rig=\"hold 1\"; /root/ahcipoc -d /dev/pass1 atapi 00 00 00 00 00 00", "code_hash": "24918cb70fe0c37b83765263ceb0725c8d930bfa5fbd3befb901fe5a8587a754", "notes": "panic = NULL-offset write (0x60)/read (0x0) in the production dispatchers; page 0 is not user-mappable on this kernel so impact stops at DoS. Natural exhaustion needs device ncqdepth < sc_ncmds (QEMU advertises 32/32) or >ncmds-1 in flight on a pruned port. Fix-validation kernel: #1 Thu Oct 15 02:34:42 UTC 2026.", "recommended_fix": "check ahci_ata_get_xfer() result for NULL in ahci_xpt_scsi_disk_io() and ahci_xpt_scsi_atapi_io() and complete the CCB with CAM_RESRC_UNAVAIL (fix.diff, validated)", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fixed", "fix_evidence": "fix-validation.log: patched kernel #1, same drain+CCB triggers -> cam_status 0x34 (CAM_RESRC_UNAVAIL|SIM_QUEUED), no panic; release -> normal CAM_REQ_CMP I/O; normal da0/dd I/O unaffected" } |