sili_pm_softreset polls with sili_quick_timeout whose sole-active KKASSERT is violated by co-active PM-target commands β XPT_RESET_DEV enters softreset without draining the port
Summary
The quick_timeout ONCHIP branch asserts sole-active, but the softreset path has no exclusive-access drain (the hardreset path does). camcontrol reset of a PM target while another target's command is on-chip and the softreset FIS times out -> KKASSERT panic on INVARIANTS; non-INVARIANTS force-completes unrelated in-flight commands as TIMEOUT (spurious CAM aborts). Drain-before-poll + demote-assert fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4694 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.4 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 | β | 143 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.1 KB | view raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 2.6 KB | view raw |
DF-4694 β sili_pm: sili_pm_softreset polls with sili_quick_timeout, whose sole-active KKASSERT is violated when other PM-target commands are still on-chip
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 = XPT_RESET_DEV storm)
Expected output
- On hardware (SiI HBA + PM, several targets active):
camcontrol reseton a PM target issues XPT_RESET_DEV β sili_cam.c:904-915 βsili_port_reset(ap, atx, 0)βsili_pm_softreset()under the port lock without draining other targets' on-chip commands. If the softreset FIS times out while any other command is still active,sili_quick_timeout()hitsKKASSERT((ap->ap_active & ~ap->ap_expired) == (1 << ccb->ccb_slot))(sili.c:2537-2538) β kernel panic (INVARIANTS is enabled in X86_64_GENERIC:56). On non-INVARIANTS builds the assert is compiled out and the code clears only its ownap_activebit then callssili_port_reinit(), force-completing the other in-flight commands as ATA_S_TIMEOUT β spurious aborts of unrelated I/O. - On the audit QEMU guest: trigger runs,
camcontrol reset 0/1succeeds benignly against the PIIX3 nata buses (run.log) β no sili HBA exists (env.txt); hardware gate, not a false positive.
Contrast: sili_pm_hardreset() drains with sili_exclusive_access() first
(sili_pm.c:272); the softreset path has no equivalent.
VERDICT β DF-4694
Status: inconclusive (hardware-gated) Β· code-path proven Β· expected impact: kernel panic (INVARIANTS KKASSERT) or spurious abort of unrelated in-flight I/O
Reproduced?
No β no sili(4) HBA / no PM emulation on the audit guest (env.txt). The
trigger runs camcontrol reset (XPT_RESET_DEV) 24+ times against the buses
that exist (ata0/ata1 under nata) β all benign (run.log); the defective
sili_pm_softreset() is unreachable here. Code-path proof below.
Why the defect is real (trace)
sili_pm_softreset()polls its softreset FIS withsili_quick_timeoutand holds the err_ccb: sili_pm.c:445-450 βif (sili_poll(ccb, timeout, sili_quick_timeout) != ATA_S_COMPLETE). The comment says quick_timeout is used because the err_ccb is held.sili_quick_timeout()'s ONCHIP branch asserts sole activity:KKASSERT((ap->ap_active & ~ap->ap_expired) == (1 << ccb->ccb_slot));β sili.c:2536-2544. The assert encodes the contract "nothing else on the chip"; on INVARIANTS kernels (X86_64_GENERIC:56, confirmed on the guest) a violation is an immediate panic.- Callers of
sili_pm_softreset()do not guarantee that contract: - XPT_RESET_DEV: sili_cam.c:904-915 takessili_os_lock_port(ap)only β no drain of other PM targets' commands β thensili_port_reset(ap, atx, 0)β sili.c:744-745 βsili_pm_softreset(). - Port-thread state machine: sili.c:632 (NEED_SOFT_RESETstep) β the preceding hardreset drained, but completions that arrived meanwhile can have queued/issued followers before this step runs. Contrast:sili_pm_hardreset()explicitly callssili_exclusive_access()first (sili_pm.c:272) β the softreset path has no equivalent. - Trigger: with β₯1 other PM-target command on-chip and the softreset FIS
timing out (1000 ms for target 15 / 8000 ms otherwise, sili_pm.c:445 β
easily exceeded behind a PM when the target is hung), the KKASSERT fires
β panic. On non-INVARIANTS builds the code proceeds to clear only its own
ap_activebit and callssili_port_reinit()(sili.c:2540-2543), which force-completes the other still-on-chip commands as ATA_S_TIMEOUT (sili.c:403-411) β spurious CAM aborts of unrelated I/O and a port reinit storm.
The trigger program drives exactly this entry point (camcontrol reset =
XPT_RESET_DEV) with a concurrent dd saturation stream; on PM hardware with a
hung target this is the deterministic panic path.
Impact ceiling
Kernel panic from an unprivileged-ish trigger (any local user can issue
camcontrol reset on a device node they can open, or the kernel reaches the
same path from error recovery); requires PM hardware and a timed timeout.
Severity Medium.
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 steps 1-4; run.log shows the XPT_RESET_DEV driver running; env.txt the hardware gate; INVARIANTS confirmed in guest /usr/src/sys/config/X86_64_GENERIC:56.
PoC changes
No seed; trigger written fresh (camcontrol reset storm is the XPT_RESET_DEV driver).
Verified recommended fix
Drain co-active commands (sili_exclusive_access) before the softreset poll, mirroring sili_pm_hardreset; downgrade the KKASSERT.
Verdict
Code-trace proven; hardware-gated: sili_pm_softreset polls with sili_quick_timeout (sili_pm.c:450) whose ONCHIP branch asserts sole activity - KKASSERT((ap->ap_active & ~ap->ap_expired) == (1 << slot)) at sili.c:2537-2538 - but XPT_RESET_DEV enters sili_pm_softreset under the port lock only, without draining other PM targets' on-chip commands (sili_cam.c:904-915 -> sili.c:744-745); contrast sili_pm_hardreset which drains via sili_exclusive_access (sili_pm.c:272). A softreset FIS timeout (1000/8000 ms) with any co-active command panics INVARIANTS kernels (X86_64_GENERIC:56, confirmed on guest); non-INVARIANTS builds force-reinit and abort the unrelated in-flight commands as ATA_S_TIMEOUT (sili.c:2540-2543 -> 403-411). Guest trigger drove 24+ camcontrol resets against ata0/ata1 benignly - no sili bus exists (env.txt).
No comments yet.