ata_ati_chipinit AHCI fallback attaches with dangling ctlr->r_res2: double bus_release_resource (rman UAF/panic) at detach
Summary
The AHCI reset-timeout error path releases r_res2 without NULLing it, and the ATI fallback treats ENXIO as attach-anyway - detach later double-releases the freed rman resource. The DF-2094 mirror shape (error-path lifetime). Hardware-gated (no 0x1002 on guest). NULL-on-release + ==0-success-test fix (git-apply verified).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5158 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 746 B | β raw | |
| VERDICT.md | β | 3.9 KB | β raw | |
| env.txt | β | 1.1 KB | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| verdict.json | β | 3.7 KB | view raw | |
| manifest.json | β | 1.1 KB | view raw |
DF-5158 β build/run
No PoC program exists for this finding: the vulnerable path requires an ATI (0x1002) IXP/SB6xx-8xx SATA controller in AHCI progif whose AHCI reset times out, plus a driver detach β none of which the QEMU audit guest can provide (guest has Intel PIIX3 IDE only; see env.txt). The defect is a statically proven error-path resource-lifetime bug, not a user-triggerable memory-safety primitive.
- Expected (on matching hardware): attach succeeds after "AHCI controller
reset failure" console message; later
kldunload/unplug β panic in rman_release_resource (double release). - Artifacts: VERDICT.md (full narrative + path:line proof), fix.diff (git-apply-able), env.txt (guest PCI/uname evidence), verdict.json.
DF-5158 β ata_ati_chipinit AHCI fallback leaves dangling ctlr->r_res2 β double bus_release_resource at detach
File: sys/dev/disk/nata/chipsets/ata-ati.c (pass 2, GLM 5.3)
What
ata_ati_chipinit() (ata-ati.c:94-120) has an AHCI fast path for ATI SB6xx/7xx/8xx
parts programmed as AHCI (subclass SATA + progif AHCI 1.0). It calls
ata_ahci_chipinit(dev) and treats ENXIO as "fall back to compat IDE mode and
attach anyway" (ata-ati.c:113). But ata_ahci_chipinit()'s error paths release
ctlr->r_res2 without NULLing the pointer:
ata-ahci.c:80-83BAR(5) alloc failure β r_res2 = NULL (clean), return ENXIO.ata-ahci.c:85-90interrupt setup failure β releases r_res2, pointer left dangling, return ENXIO. (Unreachable via ATI:ata_setup_interruptalready succeeded at ata-ati.c:99.)ata-ahci.c:94-97AHCI controller reset timeout (ata_ahci_ctlr_resetreturns ENXIO after 1000 ms, ata-ahci.c:135-141) β releases r_res2, pointer left dangling, return ENXIO. Reachable via ATI.
On the reachable path (reset timeout), ata_ati_chipinit falls through to
ctlr->setmode = ata_ati_setmode; return 0; (ata-ati.c:118-119) β attach
succeeds with a stale, already-freed ctlr->r_res2 in the softc.
The only later dereference is ata_pci_detach() (ata-pci.c:267-269):
if (ctlr->r_res2) {
bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
ctlr->r_res2 = NULL;
}
β double release of an rman resource that was already freed β rman list corruption / use-after-free β kernel panic on detach (kldunload / PCI hot-unplug / driver re-init).
Secondary defect on the same line: if (ata_ahci_chipinit(dev) != ENXIO) return 0;
treats any future non-ENXIO error return as success. Today ata_ahci_chipinit
returns only {0, ENXIO}, so the live bug is the stale-pointer one.
Trigger preconditions
- ATI/AMD SB600/SB700/SB800-family SATA controller (vendor 0x1002, ids
ATA_ATI_IXP600_S1/S2,IXP700_S1..S4,IXP800_S1/S2) programmed by BIOS with subclassPCIS_STORAGE_SATA+ progifPCIP_STORAGE_SATA_AHCI_1_0. ata_ahci_ctlr_reset()times out (GHC_HR never clears within 1 s) β i.e. a wedged/faulty controller or a pre-reset register state that sticks.- Driver detach afterwards (module unload / hot-unplug) β privileged action.
Net: privileged local DoS on flaky hardware; no info leak, no arbitrary write. Severity Low (HW-fault-gated + already-privileged trigger), CWE-459 (incomplete cleanup) shading into CWE-416 at detach.
Why untested on the guest
The audit QEMU guest has an Intel PIIX3 IDE controller (atapci0@pci0:0:1:1:
chip=0x70108086) β no ATI 0x1002 IDE/SATA PCI ID exists on the bus, so
ata_ati_ident() (ata-ati.c:66-70) never matches and the code path cannot be
instantiated. Triggering additionally requires an AHCI reset timeout, which is a
hardware fault state, not something QEMU's ich9/piix models produce for an ATI
device class that QEMU does not emulate at all. See env.txt.
The code flow itself is statically proven above (attach-success-with-stale-pointer follows mechanically from the cited lines).
Fix
fix.diff (in this directory) β two hunks:
1. ata-ahci.c: NULL ctlr->r_res2 at both release-on-error sites (root cause;
fixes every vendored caller of ata_ahci_chipinit, not just ATI).
2. ata-ati.c: treat only == 0 as AHCI success so any non-zero error falls
back to compat mode instead of masquerading as success.
fix_status: not_testable β no ATI hardware on the guest (see env.txt); the
diff is line-accurate against the audited tree but could not be boot-validated.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff is line-accurate (git apply --check passes against a clean sys/ checkout) and mechanically removes the dangling pointer at both ata-ahci.c error paths plus tightens the ATI success test to ==0, but no baseline could be reproduced on this guest (no ATI hardware), so a patched-kernel boot validation was not possible.
fix.diff in this directory; verification of applicability: 'git apply --check' => APPLIES CLEAN against sys/.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (full path:line proof); env.txt (guest pciconf: atapci0 chip=0x70108086 Intel PIIX3, no 0x1002 device => path unreachable on guest); fix.diff (git-apply-able, verified with 'git apply --check' against a clean checkout of sys/) β decisive lines: ata-ahci.c:94-97 release-without-NULL, ata-ati.c:108-119 ENXIO-means-fallback-then-return-0, ata-pci.c:267-269 detach double-release.
PoC changes
No PoC exists: the finding is hardware-gated (requires an ATI IXP/SB SATA controller in AHCI mode whose reset times out, then a detach). The audit guest has no vendor-0x1002 PCI device, so the driver never attaches.
Verified recommended fix
NULL ctlr->r_res2 at ata_ahci_chipinit's release-on-error sites and treat only ==0 as AHCI success in ata_ati_chipinit (see fix.diff).
Verdict
Statically proven error-path resource-lifetime bug, not demonstrable on the audit guest. If an ATI SB6xx/7xx/8xx SATA controller is programmed as AHCI (subclass SATA, progif AHCI 1.0) and its AHCI reset times out, ata_ahci_chipinit() releases ctlr->r_res2 without NULLing it (ata-ahci.c:94-97) and returns ENXIO; ata_ati_chipinit() treats ENXIO as 'fall back to compat IDE and attach anyway' (ata-ati.c:113,118-119), so attach succeeds with a stale already-freed resource pointer in the softc, and ata_pci_detach() later double-releases it (ata-pci.c:267-269) -> rman use-after-free/panic. The QEMU guest has only an Intel PIIX3 IDE controller (chip=0x70108086) and no vendor-0x1002 PCI device at all (env.txt), so ata_ati_ident() can never match and no PoC can exercise the path; the trigger additionally requires a hardware fault (reset timeout) plus a privileged detach, hence Low severity and status untested rather than false_positive β the code flow itself is certain from the cited lines.
No comments yet.