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

cz_ih (Carrizo/Stoney APU): unvalidated device-DMA'd IH wptr β€” 4th instance of the DF-4843/4854/4887 family: a misaligned wptr permanently hard-spins the amdgpu interrupt thread, and the RB_OVERFLOW +16 recovery imports the bad phase, parking rptr within 12 bytes of ring end for an up-to-12-byte OOB read past the zero-slack 64 KiB GTT ring BO

Summary

CZ is the wb-only variant (no use_bus_addr branch, no IH doorbell): mask-only return of the device-DMA'd wptr -> a non-16-multiple can never match the 16-byte-stepping walk (permanent ithread spin, all GPU IRQs dead); the +16 recovery imports the misaligned phase -> first decode reads up to 12 bytes past the exact-size ring BO. Byte-identical logic to the filed twins. Family sweep: after this and DF-4902, ALL FIVE IH implementations are filed - none validates alignment. Device-gated.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4901 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1.7 KB ↓ raw
VERDICT.md β€” 2.2 KB ↓ raw
trigger_sketch.c β€” 1.5 KB view raw
twin_diff.cz-vs-tonga.txt β€” 966 B view raw
fix.diff β€” 1.4 KB view raw
verdict.json β€” 2.7 KB view raw
manifest.json β€” 1.4 KB view raw
env.txt β€” 277 B view raw

DF-4901 β€” cz_ih: unvalidated device-DMA'd IH wptr (DF-4843/DF-4854/DF-4887 4th twin)

File: sys/dev/drm/amd/amdgpu/cz_ih.c (Carrizo/Stoney APUs, selected at vi.c:1671 and vi.c:1692)

CZ is the 4th member of the unvalidated-wptr IH family. All five IH implementations in the tree (cik, tonga, iceland, cz, vega10) share the same defect; after this filing and DF-4902 (iceland) every implementation is covered β€” none validates wptr alignment.

Reproduce

Not runnable on the audit guest: the wptr is DMA'd by the GPU into the host writeback slot (adev->wb.wb[adev->irq.ih.wptr_offs], cz_ih.c:192); the QEMU guest has no AMD GPU (env.txt). Code-certain by inspection β€” diff of the vulnerable block against the filed twins is empty except for the function prefix (see VERDICT.md).

The two defects (identical shape to the filed twins)

  1. Permanent interrupt-thread spin β€” cz_ih_get_wptr returns wptr & ptr_mask only (cz_ih.c:207). A wptr with phase 1..15 (mod 16) can never equal the 16-byte-stepping rptr in the shared walk (amdgpu_ih.c:154-157) β†’ the amdgpu ithread re-dispatches the whole ring forever, all GPU interrupt delivery dead.
  2. Ring-end OOB read via RB_OVERFLOW recovery β€” recovery parks rptr = (wptr + 16) & ptr_mask (cz_ih.c:202), importing the misaligned phase. For wptr' in [0xFFE4..0xFFEF]|OVERFLOW, rptr lands on [0xFFF4..0xFFFF] and the first decode (cz_ih.c:253-256) reads up to 12 bytes past the exact-64KiB GTT ring BO (cz_ih.c:300 / amdgpu_ih.c:80-88).

Artifacts

trigger_sketch.c (hostile-device pattern), fix.diff (alignment normalize + bounded walk), VERDICT.md, manifest.json, verdict.json, env.txt

VERDICT.md
↓ download raw

DF-4901 VERDICT β€” cz_ih.c 4th twin

status: untested (device-gated) | impact ceiling: dos + 12-byte OOB ring read | confidence: certain

Why untested

The audit guest (QEMU, no AMD GPU β€” env.txt) cannot instantiate cz_ih (selected only for CHIP_CARRIZO/CHIP_STONEY at vi.c:1671/1692), and the wptr source is device-side DMA into the host writeback slot (adev->wb.wb[adev->irq.ih.wptr_offs], cz_ih.c:192, targeted by the writeback programmed at cz_ih.c:133-138). Guest software cannot produce the trigger.

Why certain (code identity with filed twins)

  • cz_ih.c vs iceland_ih.c: byte-identical get_wptr/prescreen/decode/set_rptr (only OSS register headers and ip-block version differ) β€” see twin_diff.cz-vs-tonga.txt for the cz-vs-tonga shape (tonga = DF-4843, filed; tonga additionally has the use_bus_addr branch CZ lacks β€” CZ is the wb-only variant, no IH doorbell on CZ).
  • Defect 1 (spin): cz_ih.c:207 returns wptr & ptr_mask β€” no 16-byte alignment check; the shared walker (amdgpu_ih.c:154-157) steps rptr by 16 (cz_ih.c:266 decode; cz_ih.c:234 prescreen) so a wptr ≑ 4..15 (mod 16) can never be matched β†’ permanent ithread spin, all GPU IRQs dead.
  • Defect 2 (OOB): cz_ih.c:202 parks rptr=(wptr+16)&0xFFFF with the wptr's misaligned phase; wptr' ∈ [0xFFE4..0xFFEF]|OVERFLOW β†’ rptr ∈ [0xFFF4..0xFFFF] β†’ first decode (cz_ih.c:253-256) reads ring dwords [0x3FFD..0x4002] β€” up to 12 bytes past the exact-64KiB GTT ring BO allocated at cz_ih.c:300 via amdgpu_ih.c:80-88 (no slack), consumed as an IV and dispatched.

Family sweep conclusion

All five IH implementations (cik DF-4887, tonga DF-4843, vega10 DF-4854, cz DF-4901, iceland DF-4902) share the defect; after this filing and DF-4902 none remains unfiled. No IH implementation validates wptr alignment. Fix: normalize wptr alignment in each get_wptr (fix.diff here) + cap the shared walk (DF-4887's amdgpu_ih.c half).

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 authored against the read-only sys/ tree (fix.diff); not buildable/testable on this guest (no AMD GPU)

findings/poc/DF-4901/fix.diff
↓ fix.diffper-fix-DF-4901

Confirmed kernel references

Detail

Exploit chain

hostile/faulting GPU or corrupted firmware DMA writes a misaligned wptr into wb.wb[wptr_offs] -> amdgpu_ih_process (amdgpu_ih.c:154-157) can never match the 16-byte-stepping rptr -> permanent ithread spin, all GPU interrupt delivery dead; with RB_OVERFLOW set and wptr' in [0xFFE4..0xFFEF] the recovery parks rptr in [0xFFF4..0xFFFF] -> first decode (cz_ih.c:253-256) reads up to 12 bytes past the exact-64KiB GTT ring BO, consumed as an interrupt vector

Evidence (decisive lines)

VERDICT.md (code-identity argument); twin_diff.cz-vs-tonga.txt; trigger_sketch.c (armed pattern with byte arithmetic); fix.diff

PoC changes

n/a β€” no seed PoC; family-consistent trigger sketch authored

Verified recommended fix

Mask wptr to 16-byte alignment (with dev_warn) in cz_ih_get_wptr before the overflow check and derive the recovery rptr from the aligned value; cap the shared walk in amdgpu_ih_process (see DF-4887 fix.diff).

Verdict

Not runnable on the audit guest (no AMD GPU; the wptr comes from device DMA into the writeback slot, cz_ih.c:192). Code-certain by inspection: cz_ih_get_wptr (cz_ih.c:188-208) returns the device-DMA'd wptr masked only to the ring (cz_ih.c:207) with no 16-byte alignment validation, and the RB_OVERFLOW recovery (cz_ih.c:202) imports the misaligned phase into rptr=(wptr+16)&mask β€” byte-identical logic to the filed twins DF-4843 (tonga)/DF-4854 (vega10)/DF-4887 (cik); cz differs only in having no use_bus_addr branch and no IH doorbell (wb-only wptr source, CARRIZO/STONEY per vi.c:1671/1692).