⬢ DragonFlyBSD Kernel Audit
DF-4854 / trigger_sketch.c
← back to finding ↓ download raw
/*
 * DF-4854 trigger sketch — vega10_ih unvalidated IH wptr
 * (twin of DF-4843 / tonga_ih; 32-byte IV entries, 256 KiB ring)
 *
 * NOT A RUNNABLE POC. The wptr is written by the GPU into the writeback
 * shadow word at rb_dma_addr + ring_size ( programmed as the IH_RB_WPTR_ADDR
 * in vega10_ih_irq_init, vega10_ih.c:127-132 ). Forging it requires a
 * hostile/faulting Vega10 GPU (or PCI DMA master) — the audit guest has no
 * AMD GPU.
 *
 * Primitive 1 (permanent spin / GPU IRQ DoS):
 *   hostile GPU writes wptr_shadow = 0x00010004      (misaligned mod 32)
 *   -> vega10_ih_get_wptr returns 0x10004 & 0x3FFFF = 0x10004
 *   -> amdgpu_ih_process: rptr (0-phase, steps 32) can never equal 0x10004
 *   -> ithread laps the ring forever, ih->lock held, all amdgpu IRQs dead
 *
 * Primitive 2 (20-byte OOB read past the ring allocation):
 *   hostile GPU writes wptr_shadow = 0x0003FFDD      (OFFSET=0x3FFDC, RB_OVERFLOW=1)
 *   -> get_wptr: bit0 cleared -> 0x3FFDC; rptr := (0x3FFDC + 32) & 0x3FFFF = 0x3FFFC
 *   -> decode_iv: ring_index = 0xFFFF, reads ring[0xFFFF .. 0x10006]
 *      (words 0x10002..0x10006 are past dma_alloc_coherent(0x40008))
 *   -> OOB dwords become entry->src_data/timestamp/pasid and are dispatched
 *      (amdgpu_irq.c:170/173-175); also passed to amdgpu_amdkfd_interrupt.
 *
 * If a Vega10 system is available, primitive 1 can be exercised without
 * hostile DMA by poking the shadow from a kld / ddb:
 *   *(volatile uint32_t *)((uint8_t *)adev->irq.ih.ring + adev->irq.ih.ring_size) = 0x10004;
 * then send any GPU interrupt (e.g. X session / vulkaninfo) and observe the
 * amdgpu ithread peg a CPU with interrupts dead until reboot.
 */
int main(void) { return 0; }