β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4693

sili_pm: pm_read/pm_write recycle the ata_xfer while the chip still owns the slot β€” deferred poll timeout returns ATA_S_ONCHIP and the accessors put the ccb back on the free list with ap_expired processing pending

Summary

The accessors put_xfer on ANY non-COMPLETE return; when the poll timeout defers because other commands are on-chip, ata_cmd returns with state==ONCHIP - the ccb is recycled while the slot is still programmed and ap_active/expired bits set. Slot reuse trips the sili_poll KKASSERT (INVARIANTS panic); later expiry drain completes the re-issued ccb prematurely (cross-command corruption); a stale never-clearing ap_active bit wedges exclusive_access forever. DF-4503 twin. Wait-for-off-chip fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4693 Β· 11 files
FileTypeDescriptionSize
README.md β€” 1.5 KB ↓ raw
VERDICT.md β€” 3.4 KB ↓ raw
trigger_sili_pm.c β€” 3.1 KB view raw
build.sh β€” 120 B view raw
run.sh β€” 137 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.6 KB view raw
manifest.json β€” 1.4 KB view raw
verdict.json β€” 2.8 KB view raw

DF-4693 β€” sili_pm: pm register accessors recycle the ata_xfer while the chip still owns the slot (deferred-timeout returns ATA_S_ONCHIP)

Build & run

sh build.sh          # cc -O2 -Wall -o trigger_sili_pm trigger_sili_pm.c
sh run.sh            # ./trigger_sili_pm 15  (reset/rescan storm + dd saturation)

Expected output

  • On hardware (SiI HBA + PM, other-target I/O in flight): a PM register read/write (e.g. EINFO poll sili.c:530, SERR clear sili_pm.c:589, XPT_RESET_DEV softreset) that times out while other commands are still on-chip takes the deferred-timeout branch (ap->ap_active != ap->ap_expired, sili.c:2507-2510): sili_ata_cmd() returns with xa->state == ATA_S_ONCHIP (sili.c:1357-1359, 2375), sili_pm_read/pm_write treat it as plain failure and call sili_ata_put_xfer() (sili_pm.c:667 / 702) β€” the CCB returns to the free list while the slot is still programmed and ap_expired processing is pending. Consequences: sili_poll() KKASSERT on slot reuse (sili.c:1321), sili_ata_cmd_done completing a re-issued ccb / unloading the new command's live dmamap when sili_port_reinit() later drains the expired slot (sili.c:403-411 β†’ 2415-2418), and a stale ap_active bit wedging sili_exclusive_access() forever (sili.c:1437-1443).
  • On the audit QEMU guest: no sili HBA (env.txt) β€” path unreachable; hardware gate, not a false positive.

Twin of DF-4503 (ahci_pm.c); sili instance of the DF-4027 mechanism observed from the PM accessor call sites.

VERDICT.md
↓ download raw

VERDICT β€” DF-4693

Status: inconclusive (hardware-gated) Β· code-path proven Β· expected impact: kernel panic (KKASSERT) / cross-command CCB corruption / port wedge

Reproduced?

No β€” no sili(4) HBA on the audit guest and QEMU has no SiL3726 PM emulation (env.txt). The trigger builds and runs (build.log / run.log) and drives the CAM entry points (XPT_RESET_DEV, rescan) against the only buses present; the defective code is unreachable at runtime here. Full control-flow proof below; same evidence standard as the accepted DF-4503 sibling (ahci).

Why the defect is real (trace)

  1. sili_pm_read() / sili_pm_write() / sili_pm_set_feature() issue their FIS via sili_ata_cmd() β€” sili_pm.c:657 / 698 / 563.
  2. Poll path: sili_ata_cmd() β†’ sili_poll(ccb, 1000, sili_ata_cmd_timeout) β€” sili.c:2374-2375.
  3. On timeout with the command on-chip, sili_core_timeout() sets ap->ap_expired |= 1 << slot; if any other command is still active (ap->ap_active != ap->ap_expired) it prints "Deferred timeout until its safe" and returns without reinit β€” sili.c:2502-2511. The xa state remains ATA_S_ONCHIP.
  4. sili_poll() then returns ccb->ccb_xa.state β€” sili.c:1357-1359 β€” i.e. ATA_S_ONCHIP.
  5. The PM accessors treat every non-ATA_S_COMPLETE return identically: error path β†’ sili_ata_put_xfer(xa) β€” sili_pm.c:663-668 / 698-703 β€” which sili_put_ccb()s the ccb back onto ap_ccb_free with state = ATA_S_PUT (sili.c:2020-2030). The chip still owns the slot; ap_active/ap_expired bits remain set.
  6. Detonations: - a new command takes the recycled slot β†’ sili_poll()'s KKASSERT((ap->ap_expired & (1 << ccb->ccb_slot)) == 0) fires (sili.c:1321) β†’ panic on INVARIANTS kernels (X86_64_GENERIC:56); - when the remaining commands finish, sili_port_intr() calls sili_port_reinit() (sili.c:1956-1958) which drains the expired slot: ccb->ccb_xa.state = ATA_S_TIMEOUT; ccb->ccb_done(ccb); (sili.c:403-411) β†’ sili_ata_cmd_done() (sili.c:2393-2419) on a ccb that may already be re-issued for an unrelated command β†’ premature completion / stale sili_unload_prb() of the new command's live dmamap (the DF-4027 corruption signature); - if the slot never completes, the stale ap_active bit makes sili_exclusive_access() spin forever (sili.c:1437-1443) β€” permanent port-thread wedge.

Co-activity precondition

PM register traffic runs outside exclusive access in exactly the paths where other commands are on-chip: the port-thread EINFO poll (sili.c:530) and sili_pm_check_good() (sili.c:580,654 β†’ sili_pm.c:584,589,610). Only sili_pm_hardreset() drains first (sili_pm.c:272). A hung or slow PM target (1 s accessor timeout) while another target streams NCQ is the realistic trigger β€” device-timing dependent, hence confidence "likely", matching DF-4503's classification for the identical ahci defect.

Impact ceiling

Kernel panic (common, INVARIANTS) with a narrower cross-command corruption window (premature CAM completion / live-dmamap unload). 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_testable
baseline no→ patch + rebuild →patched clean

Fix 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
↓ fix.diffper-fix-DF-4693

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md trace steps 1-6 with the three detonation paths; run.log/env.txt document the hardware gate.

PoC changes

No seed; trigger written fresh (same shared program as DF-4692 pack).

Verified recommended fix

Treat ATA_S_ONCHIP from sili_ata_cmd as deferred: wait for expiry processing to complete the xa before sili_ata_put_xfer.

Verdict

Code-trace proven (twin of accepted DF-4503, ahci); hardware-gated on this guest: sili_pm_read (:657-668) and sili_pm_write (:698-703) call sili_ata_put_xfer() on ANY non-ATA_S_COMPLETE return. When the poll timeout defers because other commands are still on-chip ('Deferred timeout until its safe', sili.c:2505-2511), sili_ata_cmd returns with xa->state==ATA_S_ONCHIP (sili.c:1357-1359,2375) - the CCB is recycled onto ap_ccb_free while the chip still owns the slot and ap_expired processing is pending. Detonations: sili_poll KKASSERT on slot reuse (sili.c:1321); sili_port_reinit later completes the recycled/reissued ccb (sili.c:403-411 -> 2393-2419) causing premature completion or stale sili_unload_prb of the new command's live dmamap (DF-4027 signature); stale ap_active bit wedges sili_exclusive_access forever (sili.c:1437-1443). Co-activity precondition holds: PM register traffic runs outside exclusive access on the EINFO/check_good paths (sili.c:530,580,654).