als_intr registered before channels exist (and kept after they are freed): IRQ in the attach/detach window runs chn_intr(NULL)/chn_intr(freed) β NULL-deref/UAF panic; als_resource_free releases the I/O region before tearing down the handler
Summary
The IRQ is registered and card interrupts enabled BEFORE pcm_addchan creates the channels (ch->channel NULL in the window) and the handler has no NULL guard - chn_intr immediately evaluates CHN_LOCKOWNED(NULL): panic. The RF_SHAREABLE allocation means a sibling device's interrupt on the shared line enters the handler with no not-mine early-out during the whole window. Teardown mirrors it: pcm_unregister frees the channels while the handler remains, and the I/O region is released before teardown_intr. Hook-after-addchan + teardown-before-release fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4551 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| als_intr_window.c | β | 1.7 KB | view raw | |
| guest_hw_evidence.txt | β | 480 B | view raw | |
| fix.diff | β | 1.7 KB | view raw | |
| VERDICT.md | β | 3.5 KB | β raw | |
| README.md | β | 1.1 KB | β raw |
DF-4551 β als_intr() runs before channel objects exist (and after they are freed): chn_intr(NULL) NULL-deref panic + teardown ordering
File: sys/dev/sound/pci/als4000.c lines 783, 648-658, 852-853, 861-863, 872, 741-748.
Build / Run
Documentation/analysis PoC β the trigger is hardware behavior (an interrupt arriving in the attach or detach window), not a program:
cc -Wall -c als_intr_window.c # compile check only
On real hardware the reproducer is: install an ALS4000 sharing its IRQ line
with any active device (IRQ is requested RF_SHAREABLE, als4000.c:777), then
kldload snd_als4000 / use the card and kldunload snd_als4000 repeatedly
while the other device generates interrupts. An IRQ landing between
snd_setup_intr (als4000.c:783) and pcm_addchan (:852) executes
chn_intr(sc->pch.channel == NULL) -> CHN_LOCKOWNED(c) on NULL
(channel.c:683-694) -> panic.
Guest result
Not reproducible: no ALS4000 PCI device in the QEMU guest
(guest_hw_evidence.txt) β snd_als4000.ko loads but never attaches, so
als_intr is never registered or called.
VERDICT β DF-4551
Status: not_reproduced (hardware-gated). Impact: none on this guest (class: local kernel NULL-deref/UAF panic on real hardware β availability only, no control over data; needs the physical card).
Root cause (path:line)
Attach window β als_pci_attach (als4000.c:808-864) β als_resource_grab
(als4000.c:764-806):
sc->irqallocated RF_SHAREABLE (als4000.c:776-777) andsnd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr, sc, &sc->ih)runs at als4000.c:783-787 β the handler is live from here on.als_initenables card interrupts:als_gcr_wr(sc, ALS_GCR_MISC, v | 0x28000)(als4000.c:703-704), andmixer_initimmediately pokes the mixer for every device (mixer.c:713-726 loop calls intoalsmix_setβals_mix_wr) β plausibly raising IRQ status bits.- The channels the handler dispatches to do not exist yet:
sc->pch/sc->rchare zeroed softc members;ch->channelis only set byalschan_initduringpcm_addchan(als4000.c:852-853, via als4000.c:204-232).
als_intr (als4000.c:640-677) has no ownership filter and no NULL
guard:
intr = als_intr_rd(sc); // :646
if (intr & 0x80) { ... chn_intr(sc->pch.channel); } // :648-651 NULL here
if (intr & 0x40) { ... chn_intr(sc->rch.channel); } // :654-657 NULL here
chn_intr(c) (sys/dev/sound/pcm/channel.c:683-694) immediately evaluates
CHN_LOCKOWNED(c) β dereferences the NULL pcm_channel β panic. Because
the IRQ is shared, another device's interrupt also enters als_intr (no
"not mine" early-out β als_intr_rd result bits 0x80/0x40 gate only the
channel dispatch, and the handler always ACKs).
Failure paths widen the window: if mixer_init or pcm_register fails,
bad_attach β als_resource_free runs late relative to the live handler;
during suspend als_pci_suspend calls als_playback_stop/als_capture_stop
and als_uninit under the lock while IRQs are already enabled.
Teardown windows β als_pci_detach (als4000.c:866-881):
pcm_unregister(dev)(:872) destroys/frees thepcm_channelobjects;als_uninit(:877) disables IRQ generation afterwards, andbus_teardown_intronly happens insideals_resource_free(:745-748) β an in-flight or shared-line IRQ in that gap dispatcheschn_intron freed channel objects (UAF).als_resource_freereleases the I/O region (:741-744) before tearing down the interrupt (:745-748); a racing handler then performsbus_space_read_1/write_1(als4000.c:121-145) on a released mapping / reallocated port range, and ACKs (als_intr_wr) to ports rman no longer owns.
Why not reproduced
No ALS4000 PCI device exists in the QEMU guest (ALS_PCI_ID0 0x40004005 β
guest_hw_evidence.txt); snd_als4000.ko loads but als_pci_attach and
therefore snd_setup_intr never run. There is no QEMU device model for the
ALS4000, so the interrupt cannot be synthesized. Confidence likely (the
NULL-window is provable from ordering; the practical trigger needs the card
and a shared/raised IRQ).
Exploit chain
None beyond panic/DoS (hardware availability race). Not memory corruption under attacker control.
Fix validation
not_testable (no hardware).
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_testablenot_testable: no ALS4000 hardware in the guest; fix.diff is line-accurate against als4000.c:764-863.
fix.diff
Confirmed kernel references
Detail
Exploit chain
real hw: card shares IRQ with busy device -> kldload/kldunload snd_als4000 during interrupts -> NULL-deref panic (attach window) or handler over freed pcm_channel objects (detach window)
Evidence (decisive lines)
VERDICT.md (window-by-window ordering analysis with channel.c:683-6994 NULL path); guest_hw_evidence.txt (no vendor 4005 PCI device; module load produces no attach); fix.diff (register IRQ after pcm_addchan + teardown_intr before I/O release)
PoC changes
No seed existed; authored analysis artifact als_intr_window.c (no runnable trigger exists without the card).
Verified recommended fix
Move snd_setup_intr after pcm_addchan and reorder als_resource_free to teardown_intr before releasing the I/O region (see fix.diff).
Verdict
Hardware-gated lifetime/ordering defect, proven from source ordering: snd_setup_intr(als_intr) runs in als_resource_grab (als4000.c:783) and als_init enables card IRQs (:703-704) before pcm_addchan creates the channels (:852-853), so any IRQ in the window dispatches chn_intr(sc->pch.channel == NULL) -> immediate NULL deref in CHN_LOCKOWNED (channel.c:683-694) -> panic; the IRQ is RF_SHAREABLE (:777) and the handler has no ownership filter. Detach keeps the handler past pcm_unregister's channel destruction (:872) and als_resource_free releases the I/O region (:742) before bus_teardown_intr (:745), so a racing handler runs over freed channels and released bus_space. Not reproducible in QEMU: no ALS4000 PCI device exists (guest_hw_evidence.txt); driver never attaches, handler never registers. Availability-only impact (panic/DoS) on real hardware.
No comments yet.