diff --git a/sys/dev/drm/radeon/evergreen_cs.c b/sys/dev/drm/radeon/evergreen_cs.c --- a/sys/dev/drm/radeon/evergreen_cs.c +++ b/sys/dev/drm/radeon/evergreen_cs.c @@ -2814,6 +2814,38 @@ count = GET_DMA_COUNT(header); sub_cmd = GET_DMA_SUB_CMD(header); + /* DF-1246: ensure the full packet BODY fits in the IB before we + * read/write ib[idx+N]. Without this, only the header word is + * bounds-checked (evergreen_cs.c:2806) and a packet placed near + * the end of the IB causes OOB read+write past the IB allocation. + * 'need' is the maximum body word count each packet type touches. */ + { + unsigned int need = 1; /* header, already validated */ + switch (cmd) { + case DMA_PACKET_WRITE: + need = (sub_cmd == 8) ? 2 : 3; + break; + case DMA_PACKET_COPY: + switch (sub_cmd) { + case 0x00: case 0x40: case 0x4d: need = 5; break; + case 0x41: need = 6; break; + case 0x44: need = 7; break; + case 0x08: case 0x49: case 0x4c: need = 9; break; + case 0x48: case 0x4b: case 0x4f: need = 10; break; + default: need = 1; break; /* bad sub_cmd: EINVAL below */ + } + break; + case DMA_PACKET_CONSTANT_FILL: need = 4; break; + case DMA_PACKET_NOP: need = 1; break; + default: need = 1; break; /* unknown cmd: EINVAL below */ + } + if ((unsigned int)idx + need > ib_chunk->length_dw) { + DRM_ERROR("DMA packet at %u needs %u dwords, IB has %u\n", + idx, need, ib_chunk->length_dw); + return -EINVAL; + } + } + switch (cmd) { case DMA_PACKET_WRITE: r = r600_dma_cs_next_reloc(p, &dst_reloc);