diff --git a/sys/dev/drm/amd/amdgpu/gfx_v8_0.c b/sys/dev/drm/amd/amdgpu/gfx_v8_0.c --- a/sys/dev/drm/amd/amdgpu/gfx_v8_0.c +++ b/sys/dev/drm/amd/amdgpu/gfx_v8_0.c @@ -1305,6 +1305,7 @@ int me, i, max_me = 4; u32 bo_offset = 0; u32 table_offset, table_size; + u32 fw_dwords; if (adev->asic_type == CHIP_CARRIZO) max_me = 5; @@ -1318,6 +1319,7 @@ fw_data = (const __le32 *) (adev->gfx.ce_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_dwords = adev->gfx.ce_fw->datasize / 4; table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); } else if (me == 1) { @@ -1326,6 +1328,7 @@ fw_data = (const __le32 *) (adev->gfx.pfp_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_dwords = adev->gfx.pfp_fw->datasize / 4; table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); } else if (me == 2) { @@ -1334,6 +1337,7 @@ fw_data = (const __le32 *) (adev->gfx.me_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_dwords = adev->gfx.me_fw->datasize / 4; table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); } else if (me == 3) { @@ -1342,6 +1346,7 @@ fw_data = (const __le32 *) (adev->gfx.mec_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_dwords = adev->gfx.mec_fw->datasize / 4; table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); } else if (me == 4) { @@ -1350,10 +1355,22 @@ fw_data = (const __le32 *) (adev->gfx.mec2_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_dwords = adev->gfx.mec2_fw->datasize / 4; table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); } + /* jt_offset/jt_size come straight from the firmware header + * with no validation. Reject values that would read past + * the firmware blob (OOB read) or write past the cp_table BO + * (OOB write). */ + if (table_size > fw_dwords || + table_offset > fw_dwords - table_size || + table_size > adev->gfx.rlc.cp_table_size / 4 || + bo_offset > adev->gfx.rlc.cp_table_size / 4 - table_size) { + dev_warn(adev->dev, "invalid CP jump table offset/size, skipping\n"); + continue; + } for (i = 0; i < table_size; i ++) { dst_ptr[bo_offset + i] = cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));