diff --git a/sys/dev/drm/amd/amdgpu/gfx_v9_0.c b/sys/dev/drm/amd/amdgpu/gfx_v9_0.c --- a/sys/dev/drm/amd/amdgpu/gfx_v9_0.c +++ b/sys/dev/drm/amd/amdgpu/gfx_v9_0.c @@ -1109,13 +1109,45 @@ table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); } else if (me == 4) { - const struct gfx_firmware_header_v1_0 *hdr = - (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; + const struct gfx_firmware_header_v1_0 *hdr; + /* DF-1177: mec2_fw is optional -- init_microcode:744 sets it to + * NULL when request_firmware fails. Skip the me==4 iteration + * in that case instead of dereferencing NULL here. */ + if (adev->gfx.mec2_fw == NULL) + continue; + hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.mec2_fw->data; fw_data = (const __le32 *) (adev->gfx.mec2_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); table_offset = le32_to_cpu(hdr->jt_offset); table_size = le32_to_cpu(hdr->jt_size); + } else { + continue; + } + + /* DF-1177: validate jt_size against the remaining cp_table + * capacity (16896 dwords minus the running offset) and the + * firmware jt_offset+table_size against the firmware data size. + * Without these checks a large jt_size writes past the cp_table + * BO and reads past the firmware buffer. */ + { + const struct firmware *_fw_me = + (me == 0) ? adev->gfx.ce_fw : + (me == 1) ? adev->gfx.pfp_fw : + (me == 2) ? adev->gfx.me_fw : + (me == 3) ? adev->gfx.mec_fw : + adev->gfx.mec2_fw; + size_t _fw_ds = (_fw_me ? _fw_me->datasize : 0); + if (_fw_me == NULL || + table_size > 16896 - bo_offset || + (size_t)table_offset > _fw_ds || + (size_t)table_size > (_fw_ds - table_offset) / sizeof(uint32_t)) { + dev_warn(adev->dev, + "rv_init_cp_jump_table: skipping me=%d jt_offset=%u jt_size=%u fw_ds=%zu\n", + me, table_offset, table_size, _fw_ds); + continue; + } } for (i = 0; i < table_size; i ++) {