Unvalidated device-DMA'd IH wptr (alignment never checked, only masked) + unbounded amdgpu_ih_process ring walk β a misaligned wptr can never equal the 16-byte-stepping rptr, permanently hard-spinning the amdgpu interrupt thread (all GPU interrupt delivery dead)
Summary
get_wptr consumes the GPU-writeback u32 with nothing but &ptr_mask; the process loop terminates on rptr==wptr with rptr stepping 16 bytes - a wptr not a multiple of 16 (hostile fw DMA, corrupted writeback after PCIe fault) can never equal rptr: the ithread laps the 64KiB ring forever re-dispatching 4096 entries/lap with ih->lock held, one CPU pegged in interrupt context and all GPU interrupt delivery dead. No entry-count cap anywhere (genuine storms wedge equally). Validate-alignment + cap-per-invocation fix. Hostile-device model; hw-gated.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4843 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.1 KB | β raw | |
| trigger_sketch.c | β | 1.8 KB | view raw | |
| verdict.json | β | 2.0 KB | view raw |
DF-4843 β unvalidated IH wptr + unbounded ring walk = permanent interrupt-thread livelock
sys/dev/drm/amd/amdgpu/tonga_ih.c + amdgpu_ih.c.
The VI IH writeback slot (adev->irq.ih.ring[wptr_offs], a device-DMA'd u32)
is consumed by tonga_ih_get_wptr() (tonga_ih.c:196-219) with nothing but a
ptr_mask β no alignment validation, no sanity bound. amdgpu_ih_process()
(amdgpu_ih.c:131-168) then walks while (ih->rptr != wptr) with rptr
advancing only in 16-byte IV steps (tonga_ih.c:245/277) and re-reads wptr in
restart_ih (amdgpu_ih.c:163-165).
A wptr that is not a multiple of 16 β arbitrary in the hostile-device model
(compromised GPU/firmware DMA), plausible in the faulting-device model
(garbage writeback after a PCIe error) β can never equal rptr: the walk
laps the 64 KiB ring forever, re-dispatching 4096 entries per lap through the
full amdgpu_irq_dispatch() chain (MMIO-heavy handlers), with ih->lock
held. Result: permanent hard-spin of the amdgpu ithread β one CPU pegged in
interrupt context, all GPU interrupt delivery dead for the life of the box.
No entry-count cap exists anywhere on the path (an interrupt storm from a
livelier hostile device keeps it equally busy even with an aligned wptr).
Status: UNTESTED
Requires a Tonga/Vega10 device (or an adev fake whose set_rptr MMIO is
stubbed) to drive the real loop; the audit guest has no GPU. The code path
is certain by inspection (see trigger_sketch.c for the exact loop-lap
argument). DoS only β no memory-safety impact found on this file's surface:
entry reads are bounded by rptr & ptr_mask + 4-dword entries inside the
64 KiB + 8 allocation, src_id/client_id are bounds-checked in dispatch
(amdgpu_irq.c:409-417), and the NULL .process sibling issue is DF-4713.
Suggested fix
Validate wptr alignment/relationship in the amdgpu_ih_get_wptr
implementations (tonga_ih.c:218: reject/align wptr & ~0xf mismatch with a
dev_err + ring reset), and cap the per-invocation entry count in
amdgpu_ih_process() (amdgpu_ih.c:154) so a storm or a bad wptr yields to
the scheduler instead of hard-spinning the ithread.
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
README.md (loop-lap argument with path:line); trigger_sketch.c
PoC changes
sketch only; no runnable PoC without hardware
Verified recommended fix
validate wptr alignment in tonga_ih_get_wptr (reject/repair wptr & ~0xf mismatch with a ring reset) and cap per-invocation entry count in amdgpu_ih_process so a storm or bad wptr cannot hard-spin the ithread
Verdict
Not run on the audit guest (requires a Tonga/Vega10 GPU or an adev fake with stubbed set_rptr MMIO; the guest has no GPU). Code-certain by inspection: tonga_ih_get_wptr (tonga_ih.c:196-219) returns the device-DMA'd writeback wptr with only a ptr_mask - no alignment check - and amdgpu_ih_process (amdgpu_ih.c:154-165) walks the ring with rptr advancing strictly in 16-byte steps and restart_ih re-reading the same wptr. A wptr not a multiple of 16 can never equal rptr, so the ithread laps the 64KiB ring forever re-dispatching entries with ih->lock held: permanent interrupt-thread hard-spin (one CPU pegged, all GPU interrupts dead). Hostile/faulting-device DoS only; no memory-safety issue on this path (entry reads masked+bounded, src_id/client_id checked in dispatch).
No comments yet.