DF-4502 / verdict.json
{ "finding_id": "DF-4502", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Code defect is certain by mechanical trace: ahci_pm_softreset() releases the reserved error CCB only when it retries (ahci_pm.c:811) and jumps to err: without ahci_put_err_ccb() on the final second-FIS failure (ahci_pm.c:805-817), leaving AP_F_ERR_CCB_RESERVED set forever and ap_active/ap_sactive/ap_active_cnt zeroed (saved only at ahci.c:3356-3364, restored only at ahci.c:3407-3412). The port then wedges (ahci.c:2319-2322 refuses to issue anything) and the next ahci_get_err_ccb() on the port -- e.g. via camcontrol rescan -> wildcard XPT_PATH_INQ -> ahci_port_state_machine (ahci_cam.c:920-923) -> ahci_pm_port_probe (ahci.c:1710, ahci_pm.c:188) -- trips KKASSERT at ahci.c:3352, a real panic on INVARIANTS kernels (X86_64_GENERIC:56; sys/sys/systm.h:98-101). Runtime reproduction was impossible: the audit QEMU guest has no AHCI controller (PCI inventory: PIIX3 IDE atapci0 + virtio only, env.txt) and QEMU does not emulate SATA port multipliers, so the priming condition (PM softreset double-failure) cannot occur on any available emulation. The detonator trigger builds and runs on the guest (build.log/run.log: 64 wildcard rescans against the ata CAM buses complete without error -- the ahci sink is simply absent). Expected real-hardware impact: kernel panic / permanent port I/O hang (local DoS) on machines with a port multiplier and a flaky target.", "exploit_chain": "", "evidence": "VERDICT.md (full line-cited trace incl. the 752-767 vs 805-817 asymmetry and the re-entry chain); run.log (detonator runs clean on guests CAM buses); env.txt (no AHCI controller on guest); fix.diff (git-apply --check OK)", "kernel_refs": [ "sys/dev/disk/ahci/ahci_pm.c:719", "sys/dev/disk/ahci/ahci_pm.c:752-767", "sys/dev/disk/ahci/ahci_pm.c:805-817", "sys/dev/disk/ahci/ahci_pm.c:862-877", "sys/dev/disk/ahci/ahci.c:3352", "sys/dev/disk/ahci/ahci.c:3364", "sys/dev/disk/ahci/ahci.c:3407-3412", "sys/dev/disk/ahci/ahci.c:2319-2322", "sys/dev/disk/ahci/ahci.c:1710", "sys/dev/disk/ahci/ahci_cam.c:920-923", "sys/sys/systm.h:98-101", "sys/config/X86_64_GENERIC:56" ], "poc_changes": "Seed sketch did not exist; wrote the detonator from scratch. First variant used <cam/cam.h> + CAMIOCOMMAND directly but the clean-install guest ships no CAM userland headers (build_failed), so the final version shells out to /sbin/camcontrol rescan (same XPT wildcard PATH_INQ path). Bus argument default corrected from 2 to a guest-existing bus after camcontrol EINVAL on bus 2.", "attempts": 3, "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": 95, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o trigger_DF4502 trigger_DF4502.c", "run_cmd": "./trigger_DF4502 0 (64 x camcontrol rescan; root)", "code_hash": "91dc7f75ee2cdb5836c9c11ab9cc5009397773114ff9860a5a2617759cb5d7b8", "notes": "Bug family distinct from known DF-1659/DF-2423 (those are the NULL deref when ahci_ata_get_xfer returns NULL in the same two functions; this is a reservation/lifecycle leak in ahci_pm_softreset, a different function and mechanism). Non-INVARIANTS kernels do not panic on the KKASSERT (systm.h:118) but the port wedges silently with corrupted completion accounting, and ahci_put_err_ccbs plain panic at ahci.c:3393/3399 remains reachable.", "recommended_fix": "Release the error CCB unconditionally in the second-FIS failure branch before the retry decision, mirroring the first-FIS branch (ahci_pm.c:756) and ahci_port_softresets err-label discipline (ahci.c:1393-1394); see fix.diff.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Fix authored (fix.diff, git-apply --check clean) but not kernel-buildable into a testable configuration: the bug requires PM hardware absent from the only emulation available (no AHCI controller on the guest; QEMU has no port-multiplier emulation), so baseline-vs-patched comparison cannot be performed.", "fix_evidence": "fix.diff (git apply --check OK on the read-only sys/ tree; never applied); VERDICT.md Fix validation section." } |