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

cs4281_pci_detach() releases the BA0/BA1 register mappings before bus_teardown_intr - live ISR reads released mappings (shared-IRQ use-after-release window)

Summary

Detach releases the register windows before tearing down the interrupt; the ISR bus_space-reads HISR/HDSR through exactly those mappings on every dispatch on a shareable IRQ. An interrupt in the window dispatches into released rman resources (panic); the bad: unwind repeats the inverted order. Sibling es137x does it correctly. Teardown-intr-first fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4538 Β· 12 files
FileTypeDescriptionSize
README.md β€” 1.6 KB ↓ raw
VERDICT.md β€” 2.4 KB ↓ raw
cs4281_probe.c β€” 2.0 KB view raw
build.sh β€” 133 B view raw
run.sh β€” 138 B view raw
build.log β€” 94 B view raw
run.log β€” 428 B view raw
env.txt β€” 604 B view raw
wedge_episode.txt β€” 777 B view raw
fix.diff β€” 793 B view raw
manifest.json β€” 975 B view raw
verdict.json β€” 3.1 KB view raw

DF-4538 β€” cs4281_pci_detach() releases the BA0/BA1 register mappings before tearing down the interrupt handler that reads them

What this is

cs4281_pci_detach() (cs4281.c:878-901) releases the BA0 register window (cs4281.c:893) and the BA1 memory window (cs4281.c:894) before bus_teardown_intr() (cs4281.c:895). The interrupt handler (cs4281_intr, registered at cs4281.c:812, shared-IRQ capable per cs4281.c:806 RF_SHAREABLE) reads CS4281PCI_HISR/HDSR through those mappings (cs4281_rd, cs4281.c:146-150) on every line assertion, and pcm_unregister() does not unregister the handler. During the window between the two releases and the teardown, an interrupt (its own or a shared line level) dispatches into bus_space reads of already-released rman resources β€” use-after-release of the register mapping, typically a kernel panic.

Sibling drivers get the order right (es137x.c:1917-1919 tears down the interrupt before releasing IRQ and registers); cs4281 (and its bad: unwind at cs4281.c:867-870, which has the same inverted order) does not.

Trigger: root unloading snd_cs4281 (kldunload) while the device raises or shares an interrupt. Unprivileged users cannot reach this; severity Low.

Build / run

./build.sh    # guest build of the environment probe
./run.sh      # documents: no CS4281 hardware on this guest (detach path unreachable)

Fix

fix.diff moves bus_teardown_intr() + IRQ release ahead of the BA0/BA1 register releases in cs4281_pci_detach(), matching es137x.c:1917-1919. git apply --check clean; never applied to sys/.

VERDICT.md
↓ download raw

DF-4538 VERDICT β€” untested (hardware-gated), analysis certain

Source chain

  1. snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih) at cs4281.c:812 installs the ISR; the IRQ resource was allocated RF_SHAREABLE (cs4281.c:805-806).
  2. cs4281_intr (cs4281.c:512-533) immediately reads cs4281_rd(sc, CS4281PCI_HISR) (cs4281.c:517) β€” i.e. a bus_space read through sc->st/sc->sh, the BA0 mapping β€” before deciding whether the interrupt is ours (there is no early filter/ITHREAD filter separation here).
  3. cs4281_pci_detach (cs4281.c:878-901) first calls pcm_unregister (cs4281.c:884) β€” which stops channels/mixer but does not unregister the ISR β€” then releases the BA0 register resource (cs4281.c:893) and BA1 memory (cs4281.c:894), and only then runs bus_teardown_intr (cs4281.c:895).
  4. In the window between (3)'s releases and the teardown, any interrupt on the (shared) line dispatches cs4281_intr into reads of released rman-backed mappings β†’ use-after-release; typical outcome panic.
  5. The bad: attach-unwind has the same inverted order (cs4281.c:867-870: bus_teardown_intr after the two bus_release_resource calls), though reaching it additionally requires an attach failure.
  6. Correct ordering exists in the sibling es137x driver (es137x.c:1917-1919: teardown_intr, release IRQ, release regs).

Why untested

Requires a real CS4281 PCI function to exist (so attach succeeded and detach can run) plus root (kldunload snd_cs4281) plus an interrupt arrival inside the release window. The audit guest has no vendor-1013 function (env.txt, run.log) β€” the detach path cannot execute here at all. Static chain verified line-by-line; classification untested, confidence certain, no unprivileged impact (root-gated) β†’ Low.

Fix validation

fix.diff reorders detach to teardown_intr β†’ IRQ release β†’ BA0/BA1 release. git apply --check clean. Not observable on this guest (no CS4281 hardware) β†’ fix_status not_testable.

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.diff moves bus_teardown_intr() and the IRQ release ahead of the BA0/BA1 register releases in cs4281_pci_detach(); git apply --check is clean. Not observable on the audit guest (no CS4281 hardware), so baseline vs patched cannot be compared.

findings/poc/DF-4538/fix.diff; correct sibling order at es137x.c:1917-1919
↓ fix.diffper-fix-DF-4538

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-4538/VERDICT.md; cs4281.c:812 snd_setup_intr, cs4281.c:805-806 RF_SHAREABLE, cs4281.c:517/523/528 ISR register reads, cs4281.c:893-895 inverted release order, cs4281.c:867-870 same order in bad:, es137x.c:1917-1919 correct sibling order; run.log/env.txt (no vendor-1013 PCI function on guest)

PoC changes

no seed; environment probe shared with DF-4537 (same trigger-hardware absence)

Verified recommended fix

In cs4281_pci_detach (and the bad: unwind), call bus_teardown_intr and release the IRQ before releasing the BA0/BA1 register resources, matching es137x.c:1917-1919

Verdict

cs4281_pci_detach() (cs4281.c:878-901) releases the BA0 register window (cs4281.c:893) and BA1 memory window (cs4281.c:894) before bus_teardown_intr() (cs4281.c:895), while cs4281_intr -- installed at cs4281.c:812 on a shareable IRQ (cs4281.c:805-806) -- bus_space-reads HISR/HDSR through exactly those mappings on every dispatch (cs4281.c:517,523,528) and pcm_unregister() (cs4281.c:884) does not unregister it. An interrupt arriving in the release window dispatches into released rman mappings: use-after-release, typical outcome panic. The bad: attach-unwind repeats the same inverted order (cs4281.c:867-870). Sibling es137x.c:1917-1919 demonstrates the correct teardown-first order. Untested: executing detach at all requires a CS4281 PCI function (absent on the audit guest, env.txt) and root (kldunload); the race window needs an interrupt arrival. Root-gated, hardware-gated: Low, analysis certain.