Unchecked NULL from ahci_ata_get_xfer() in ahci_set_feature() and ahci_read_log() (ahci.c instances of the DF-2420/DF-2423 class) -> kernel panic
Summary
ahci_set_feature() and ahci_read_log() dereference ahci_ata_get_xfer()'s return without a NULL check; it returns NULL when the per-port free-CCB list is empty. The pool is sc_ncmds-1 deep and CAM's devq has exactly sc_ncmds-1 openings, so concurrent I/O can hold every free CCB; xa->fis (first struct member) then faults on NULL. Same class as DF-2420 (ahci_cam.c)/DF-2423 (ahci_pm.c) - these are the two ahci.c sites neither record covers. ahci_read_log reachable from DevSleep probe during re-probe concurrent with I/O saturation (hotplug-conditioned); ahci_set_feature from the root-gated link_pwr_mgmt sysctl and DIPM negotiation. NULL-deref panic.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3774 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.4 KB | β raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| env.txt | β | 551 B | view raw | |
| fix.diff | β | 722 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
DF-3774 β ahci_set_feature() / ahci_read_log(): unchecked NULL from ahci_ata_get_xfer() β NULL-pointer kernel panic under CCB-pool exhaustion
File: sys/dev/disk/ahci/ahci.c (pass 2, GLM 5.3)
What the bug is
ahci_ata_get_xfer() (ahci.c:3669-3689) returns NULL when the per-port
CCB free list is empty (ahci_get_ccb() β NULL). Two ahci.c callers never
check:
int
ahci_set_feature(struct ahci_port *ap, struct ata_port *atx, ...)
{
...
xa = ahci_ata_get_xfer(ap, atx); /* ahci.c:4057 */
xa->fis->type = ATA_FIS_TYPE_H2D; /* ahci.c:4059 β NULL deref */
...
}
int
ahci_read_log(struct ahci_port *ap, struct ata_port *atx, ...)
{
...
xa = ahci_ata_get_xfer(ap, atx); /* ahci.c:4090 */
xa->fis->type = ATA_FIS_TYPE_H2D; /* ahci.c:4092 β NULL deref */
...
}
fis is the first member of struct ata_xfer (atascsi.h:356-358), so the
fault is a read of *(NULL + 0) β kernel panic.
This is the same defect class already filed for the sibling files: DF-2420 (ahci_cam.c dispatch sites) and DF-2423 (ahci_pm_read/write). These two ahci.c sites were not covered by either record.
Reachability
The CCB pool is sc_ncmds - 1 deep (slot 1 is the reserved error CCB,
ahci.c:431-439) and CAM's devq is sized to exactly sc_ncmds - 1 openings
(ahci_cam.c:111-115), so ordinary CAM I/O alone can hold every free CCB β
in particular CCBs in the window where ahci_xpt_scsi_*_io() has taken a CCB
(ahci_cam.c:1082/1524, under ap_sim_lock only) but is blocked in
ahci_ata_cmd() on the port lock.
- ahci_read_log is called from
ahci_cam_probe_disk()(ahci_cam.c:605, DevSleep identify support) during (re)probe, which runs while the port lock is held for seconds (PM probe sleeps 5s) β CAM submissions from other CPUs can hold all free CCBs in that window β NULL deref. - ahci_set_feature is called from
ahci_port_link_pwr_mgmt()(ahci.c:634, 641, 688, 695, 718, 721 β sysctlhw.ahci.X.link_pwr_mgmt, root-gated) and from DIPM/APST negotiation.
Impact: NULL-deref panic (local DoS). Combined severity capped at Low for this file's sites (probe-path variant is hotplug/PM-conditioned; sysctl variant is root-gated) β see DF-2420/2423 for the class discussion.
Why not reproduced on the guest
No AHCI controller on the audit guest (env.txt); the probe/link-pm paths cannot execute. Class precedent (DF-2420) documents the exhaustion mechanics.
DF-3774 VERDICT β not_reproduced (no AHCI hardware on guest); NULL-deref sites certain by source
Bottom line
ahci_set_feature() (ahci.c:4047-4077) and ahci_read_log()
(ahci.c:4080-4115) call ahci_ata_get_xfer() (ahci.c:3669-3689) and
immediately dereference the result (xa->fis->type = ... at ahci.c:4059 and
ahci.c:4092) without a NULL check. ahci_ata_get_xfer() returns NULL whenever
the per-port free-CCB list is empty. fis is the first field of
struct ata_xfer (atascsi.h:356-358), so a NULL xa faults on the next line β
kernel panic.
Pool-exhaustion is reachable because CAM's devq has exactly sc_ncmds - 1
openings (ahci_cam.c:111-115) matching the sc_ncmds - 1 free CCBs (slot 1
reserved, ahci.c:431-439): a burst of submissions grabs all free CCBs under
ap_sim_lock (ahci_cam.c:1082/1524) and holds them while blocked on the port
lock. ahci_read_log runs from ahci_cam_probe_disk() (ahci_cam.c:605) during
probe β which holds the port lock for seconds during PM probing β and
ahci_set_feature runs from the hw.ahci.X.link_pwr_mgmt sysctl
(ahci_dragonfly.c:150-162 β ahci.c:595-752) and DIPM negotiation.
Same class as DF-2420 (ahci_cam.c) and DF-2423 (ahci_pm.c); those records cover their files' sites, these are the two unfiled ahci.c sites.
Not-reproduced rationale
Guest has no AHCI controller (env.txt) β neither probe nor link-pm paths can run. NULL-deref on exhaustion is certain from source; runtime frequency depends on I/O concurrency (documented for the class in DF-2420).
Recommended fix
Check for NULL and return EBUSSE/EIO:
xa = ahci_ata_get_xfer(ap, atx);
if (xa == NULL)
return (EBUSY); /* or EIO for read_log */
see fix.diff.
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_testableTwo-line guard authored; cannot be exercised without AHCI hardware.
fix.diff in this pack.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md; ahci.c:4057+4059 and ahci.c:4090+4092 (unchecked deref); ahci.c:3674-3679 (get_xfer NULL path); ahci.h/atascsi.h:356-358 (fis is first member); ahci_cam.c:111-115 (devq openings == pool depth)
PoC changes
No runtime PoC - no AHCI hardware on guest; class mechanics documented in DF-2420/DF-2423.
Verified recommended fix
NULL-check the ahci_ata_get_xfer() return in ahci_set_feature and ahci_read_log and return EBUSY.
Verdict
ahci_set_feature() (ahci.c:4057/4059) and ahci_read_log() (ahci.c:4090/4092) dereference the return of ahci_ata_get_xfer() without a NULL check; the function returns NULL when the per-port CCB free list is empty (sc_ncmds-1 slots, all holdable by concurrent CAM submissions whose devq has exactly that many openings, ahci_cam.c:111-115). NULL xa faults on xa->fis (first struct member) - kernel panic. ahci_read_log is reached from DevSleep probe (ahci_cam.c:605) and ahci_set_feature from the root-gated link_pwr_mgmt sysctl and DIPM negotiation. Same defect class as DF-2420/DF-2423; these are the ahci.c sites neither record covers. Not reproduced: guest has no AHCI controller.
No comments yet.