OOB read in DHRS error path: device-controlled CCS slot index dereferenced before bounds check
Summary
ahci_port_intr() DHRS branch at ahci.c:2843-2851: err_slot=AHCI_PREG_CMD_CCS(ahci_pread) is 5-bit (0-31), but ap_ccbs[] allocated for sc_ncmds (4-32). ccb=&ap->ap_ccbs[err_slot] at :2847 BEFORE bounds check. Then ccb->ccb_xa.fis->command derefs OOB ccb then garbage fis pointer -> kernel panic. TFES path at :2724 correctly checks err_slot<ncmds first, DHRS path does NOT. Malicious/buggy AHCI controller (PCIe passthrough/Thunderbolt) sets CCS>=ncmds on DHRS error. Fix: add bounds check err_slot>=sc_ncmds before ap_ccbs indexing.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1210 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | full path:line trace + reachability analysis | 3.9 KB | β raw |
| README.md | readme | claim, verdict, threat model, fix | 2.0 KB | β raw |
| fix.diff | suggested-fix | bounds-check DHRS err_slot vs sc_ncmds before ap_ccbs[] deref (mirrors TFES guard) | 583 B | view raw |
| run.sh | reachability-probe | shell probe: is an AHCI controller attached? | 798 B | view raw |
| build.sh | build-noop | no userspace build (trigger is AHCI CCS hardware register) | 281 B | view raw |
| fix_build.log | build-log | GENERIC kernel build with the fix applied (rc=0; ahci.o/ahci.ko clean) | 5.6 MB | β download |
| env.txt | environment | guest uname, cc, device topology | 718 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1210 β OOB read in AHCI DHRS error path (device-controlled CCS slot)
Claim
ahci_port_intr() DHRS branch (sys/dev/disk/ahci/ahci.c:2843-2851):
err_slot = AHCI_PREG_CMD_CCS(ahci_pread(...)) is a 5-bit value (0-31)
read from the AHCI controller, but ap->ap_ccbs[] is sized for
sc->sc_ncmds (4-32). The code does ccb = &ap->ap_ccbs[err_slot]
(ahci.c:2847) and derefs ccb->ccb_xa.fis->command (ahci.c:2850)
before any bounds check. The TFES path (ahci.c:2724) correctly
checks err_slot < 0 || err_slot >= sc_ncmds first; the DHRS path does not.
A malicious/buggy AHCI controller returning a CCS >= sc_ncms yields an OOB
ap_ccbs[] index then a deref of a garbage fis pointer β kernel panic /
controlled memory access.
Verdict
NOT TESTABLE on this audit guest (real bug, traced line-by-line; fix
authored and compile-validated into the GENERIC kernel). See VERDICT.md.
Why not reproduced here
- The guest has no AHCI/SATA controller:
pciconf -lshows none; the disk is virtio-blk (/dev/vbd0).ahci(4)did not attach, soahci_port_intr()is never called. - Even with an AHCI controller present, the malicious value comes from the
controller's CCS hardware register, not from any userspace syscall. The
benign QEMU AHCI model always reports a valid CCS, so there is no
unprivileged path to drive
err_slot >= sc_ncmds.
Trigger (threat model)
A malicious or faulty AHCI controller (PCIe peripheral, Thunderbolt
storage-bridge, or a malicious VM host's AHCI device model attacking a
guest) that raises a DHRS interrupt with ERR set and CCS >= sc_ncmds.
Common in the real world via buggy controllers and is a class of
DMA/peripheral attack surface.
Fix
fix.diff mirrors the TFES bounds check (err_slot < 0 || err_slot >= sc_ncmds)
immediately after reading CCS and before the ap_ccbs[err_slot] deref,
routing a bad slot to the existing process_error machinery (which re-reads
CCS and the TFES path's check then resets the port).
DF-1210 β VERDICT
Finding: OOB read in the AHCI DHRS error path: a device-controlled CCS
slot index is dereferenced before any bounds check
(sys/dev/disk/ahci/ahci.c).
Status: NOT TESTABLE on this audit guest. Confidence (bug is real): certain.
Impact ceiling: kernel OOB array index + garbage-pointer deref β panic /
controlled memory access; device-controlled (malicious AHCI controller).
Fix: authored in fix.diff, applied clean, compile-validated into the
GENERIC kernel (fix_build.log).
Mechanism (confirmed line-by-line in sys/)
ahci_port_intr()(ahci.c) handles the DHRS (D2H Register FIS) interrupt.ahci.c:2643βint err_slot;declared inside the TFES block;process_error:label is atahci.c:2651.- DHRS branch
ahci.c:2809(else if (is & AHCI_PREG_IS_DHRS)): -ahci.c:2832-2833readstfd(PxCMD_TFD) andcmd(PxCMD). -ahci.c:2843-2844β on(tfd & ERR) && !(cmd & ST): -ahci.c:2845-2846βerr_slot = AHCI_PREG_CMD_CCS(ahci_pread(ap, AHCI_PREG_CMD));AHCI_PREG_CMD_CCS(_r) = ((_r) >> 8) & 0x1f(ahci.h:183) β 5-bit, 0-31. -ahci.c:2847βccb = &ap->ap_ccbs[err_slot];NO bounds check.ap_ccbs[]is allocated forsc->sc_ncmdsslots (4-32, set from the controller's CAP.NCS). -ahci.c:2850βkprintf("... cmd=%02x", ..., ccb->ccb_xa.fis->command)β derefs the OOBccbthen a garbagefispointer. -ahci.c:2851βgoto process_error;carries the (still unchecked) slot. - Compare the TFES path, which does validate first:
ahci.c:2724βelse if (err_slot < 0 || err_slot >= ap->ap_sc->sc_ncmds) { ... err_slot=-1; }. The DHRS path is the asymmetric, missing-check sibling.
So a CCS value in [sc_ncmds .. 31] indexes past ap_ccbs[]. The damage
(read of OOB ccb, then fis->command deref) occurs at ahci.c:2847-2850
before any later check can run.
Why it is NOT TESTABLE on this guest
pciconf -llists no AHCI/SATA controller; the guest root disk is virtio-blk (/dev/vbd0), the only storage besides a SCSI DVD-ROM.ahci(4)is in GENERIC but did not attach to any device, soahci_port_intr()is dead code at runtime here.- The attacker-controlled input (
err_slotvia CCS) is a hardware register read from the AHCI controller. On a benign controller CCS is always a slot the driver actually issued (< sc_ncmds). There is no userspace syscall that can make a benign QEMU AHCI model return CCS >= sc_ncmds, so even if an AHCI device were added it would not fire from an unprivileged user.
Valid "device-controlled, not reachable from an unprivileged user on this guest" case. The bug is genuine (asymmetric missing bounds check confirmed against the sibling TFES path); threat model = malicious/buggy AHCI controller (peripheral / malicious VM device-model).
Exploit chain
None developed: the primitive is reachable only via a malicious AHCI controller's CCS register, not via any unprivileged local syscall. On this guest there is additionally no AHCI device at all. Documented impact ceiling: panic / OOB memory access driven by the controller.
Fix
fix.diff adds the same bounds check the TFES path uses, immediately after
the CCS read and before ap_ccbs[err_slot]:
err_slot = AHCI_PREG_CMD_CCS(ahci_pread(ap, AHCI_PREG_CMD));
if (err_slot < 0 || err_slot >= ap->ap_sc->sc_ncmds) {
kprintf("%s: DHRS bad error slot %d\n", PORTNAME(ap), err_slot);
err_slot = -1;
goto process_error;
}
ccb = &ap->ap_ccbs[err_slot];
A bad slot is routed through process_error (which re-reads CCS and falls
into the TFES err_slot < 0 β failall/reset handling). Minimal, targeted,
symmetric with the existing TFES guard.
Build / run on this guest
./build.sh && ./run.sh is a reachability probe. On this guest it reports
"no ahci controller attached β DHRS path unreachable"; the bug is confirmed
by the source trace above and the fix is compile-validated into GENERIC.
Fix verification
not_testablecompile validated -Werror
module/kernel build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. ahci DHRS err_slot=CCS no bounds check vs ap_ccbs[sc_ncmds]. No AHCI controller.
No comments yet.