sili_pm: sili_pm_read/sili_pm_write/sili_pm_set_feature dereference unchecked sili_ata_get_xfer() NULL β kernel panic when any PM register access runs against an exhausted ccb pool
Summary
All three PM register accessors take an ata_xfer from the shared ccb pool with no NULL check - the very next statement writes xa->fis->type, faulting the NULL page. CAM I/O coexists with port-thread PM maintenance (every PM hot-plug pass makes 1-3 PM accesses), so a port saturated with NCQ plus one hot-plug event yields panic. Same class as DF-4237 - three further unchecked instances. Hardware-gated on guest (no sili HBA); full code-trace + trigger. NULL-check + fail-soft fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4692 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.7 KB | β raw | |
| VERDICT.md | β | 3.0 KB | β raw | |
| trigger_sili_pm.c | β | 3.1 KB | view raw | |
| build.sh | β | 120 B | view raw | |
| run.sh | β | 148 B | view raw | |
| build.log | β | 106 B | view raw | |
| run.log | β | 1.1 KB | view raw | |
| env.txt | β | 664 B | view raw | |
| fix.diff | β | 1.2 KB | view raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 2.7 KB | view raw |
DF-4692 β sili_pm: sili_pm_read / sili_pm_write / sili_pm_set_feature dereference unchecked sili_ata_get_xfer() NULL β kernel panic on ccb-pool exhaustion
Build & run
sh build.sh # cc -O2 -Wall -o trigger_sili_pm trigger_sili_pm.c sh run.sh # ./trigger_sili_pm 15 (camcontrol reset/rescan storm)
Expected output
- On hardware with a SiI 3124/3132 HBA + SiL3726 PM, port saturated with
I/O: any hot-plug async-notify event (or the periodic PM state machine
pass) makes the port thread call
sili_pm_read(ap, 15, SATA_PMREG_EINFO, β¦)(sili.c:530) /sili_pm_check_good()(sili.c:580,654 β sili_pm.c:584,589,610). With every command slot busy,sili_ata_get_xfer()returns NULL (sili.c:2322-2327) andxa->fis->type = β¦(sili_pm.c:645) faults the NULL direct-map page β kernel panic. - On the audit QEMU guest: trigger builds and runs to completion against ata0/ata1 (no sili HBA exists; see env.txt) β the defective code is never reached. This is a hardware gate, not a false positive.
Root cause chain (path:line)
sili_get_ccb()returns NULL whenap_ccb_freeis empty β sili.c:2008-2014.sili_ata_get_xfer()propagates the NULL β sili.c:2322-2327.sili_pm_set_feature()dereferences without check β sili_pm.c:549-551.sili_pm_read()dereferences without check β sili_pm.c:643-645.sili_pm_write()dereferences without check β sili_pm.c:680-682.- Live entries: PM hot-plug state machine EINFO poll (sili.c:530),
sili_pm_check_good()(sili_pm.c:584,589),sili_pm_identify()(sili_pm.c:170-217),sili_pm_hardreset()(sili_pm.c:283-340).
Same defect class as DF-4237 (sili_cam.c, pass 1) β three further unchecked instances in this file.
VERDICT β DF-4692
Status: inconclusive (hardware-gated) Β· code-path proven Β· expected impact: kernel panic (local DoS)
Reproduced?
No β and provably not runnable on this guest: the audit QEMU guest has no
SiI 3124/3132 HBA (PCI inventory in env.txt: PIIX3 IDE + virtio only, 7
devices) and QEMU does not emulate the SiL3726 port multiplier, so sili(4)
never attaches (dmesg has zero "sili" lines) and sili_pm_* is unreachable
at runtime. The trigger builds (build.log) and runs (run.log): 24+
XPT_RESET_DEV / rescan operations were driven against the only buses present
(ata0/ata1, nata driver) β benign, as expected when the sink is absent. This
is the same evidence standard as the accepted DF-4502/DF-4503 sibling packs.
Why the defect is real (trace)
sili_get_ccb()β sili.c:2003-2018 β returnsTAILQ_FIRST(&ap->ap_ccb_free)unchanged when the free list is empty, i.e. NULL is a designed return.sili_ata_get_xfer()β sili.c:2317-2337 β propagates it:if (ccb == NULL) { DPRINTF("NULL ccb"); return (NULL); }(:2322-2327).sili_pm_set_feature()β sili_pm.c:549-551:xa = sili_ata_get_xfer(ap, &ap->ap_ata[15]); xa->fis->type = β¦β no check.sili_pm_read()β sili_pm.c:643-645 β same unchecked deref.sili_pm_write()β sili_pm.c:680-682 β same unchecked deref. On NULL xa,xa->fisloads from ~offset 0x10 of the direct map β supervisor fault on the NULL page β kernel panic.
Reachability of pool exhaustion on a PM port
The port-thread PM state machine issues sili_pm_read(ap, 15, EINFO) on every
hot-plug notification pass (sili.c:529-534) and sili_pm_check_good() performs
up to three further PM accesses per event (sili_pm.c:584, 589, 610). These run
under the port lock, but commands issued before the event still occupy slots
(ap_active). CAM I/O and PM maintenance are not mutually exclusive
(sili_cam_action() issues under ap_sim_lock, sili_cam.c:122/202), so a
saturated port (all SILI_MAXCMDS slots busy β e.g. NCQ depth against a PM with
several disks) plus one async-notify interrupt yields NULL at step 3/4/5.
ata_xfer has no reserved slot for PM maintenance (the err_ccb reservation is
only for error recovery, sili.c:2033-2050).
This is the same class as DF-4237 (sili_cam.c probe NULL deref, pass 1, Medium) β three additional unchecked instances live in this file, including the periodic EINFO poll that re-fires on every hot-plug event.
Realistic impact ceiling
Kernel panic (unprivileged trigger: any user keeping the disks busy while a
hot-plug event / camcontrol rescan lands). No write primitive β NULL-page
read/write fault. Severity Medium, consistent with DF-4237.
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 validation not testable: the guest has no SiI 3124/3132 HBA and QEMU does not emulate the SiL3726 port multiplier, so neither baseline nor patched kernel can reach sili_pm_* at runtime. fix.diff is a line-accurate source-level fix (all referenced helpers declared in sili.h); code-reviewed only.
env.txt (PCI inventory, 0 sili dmesg lines); fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md 'Why the defect is real' steps 1-5; env.txt proves the hardware gate; run.log shows the trigger driving 24+ XPT reset/rescan ops against the only buses present (ata0/ata1, nata).
PoC changes
No seed existed; trigger written fresh for this pack (stdarg.h fix applied during guest build).
Verified recommended fix
NULL-check sili_ata_get_xfer() result in sili_pm_set_feature/sili_pm_read/sili_pm_write and return EBUSY.
Verdict
Code-trace proven; not runtime-triggerable on the audit guest because no sili(4) HBA exists there (hardware-gated, not a false positive): sili_ata_get_xfer() returns NULL when the ccb free list is empty (sili.c:2322-2327 -> 2003-2018) and sili_pm_read (sili_pm.c:643-645), sili_pm_write (:680-682) and sili_pm_set_feature (:549-551) dereference xa->fis unconditionally. Live entry: every PM hot-plug async-notify pass runs sili_pm_read(ap,15,EINFO) from the port thread (sili.c:530) and sili_pm_check_good performs up to three more PM accesses per event (sili_pm.c:584,589,610); CAM I/O (issued under ap_sim_lock, sili_cam.c:122/202) coexists with port-thread PM maintenance, so a saturated port + one hot-plug event = NULL deref -> panic. Same class as DF-4237 (sili_cam.c), three further instances.
No comments yet.