DF-3860 / fix.diff
--- a/sys/dev/drm/amd/amdgpu/amdgpu_device.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_device.c @@ -1367,18 +1367,45 @@ } hdr = (const struct gpu_info_firmware_header_v1_0 *)adev->firmware.gpu_info_fw->data; + + /* the common header itself must fit before we dereference it */ + if (adev->firmware.gpu_info_fw->datasize < sizeof(*hdr)) { + dev_err(adev->dev, + "gpu_info firmware \"%s\" too small (%zu bytes)\n", + fw_name, adev->firmware.gpu_info_fw->datasize); + err = -EINVAL; + goto out; + } + amdgpu_ucode_print_gpu_info_hdr(&hdr->header); switch (hdr->version_major) { case 1: { - const struct gpu_info_firmware_v1_0 *gpu_info_fw = - (const struct gpu_info_firmware_v1_0 *)(adev->firmware.gpu_info_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + u64 off = le32_to_cpu(hdr->header.ucode_array_offset_bytes); + const struct gpu_info_firmware_v1_0 *gpu_info_fw; + + /* DF-3860: payload must be inside the firmware buffer */ + if (off > adev->firmware.gpu_info_fw->datasize || + adev->firmware.gpu_info_fw->datasize - off < + sizeof(struct gpu_info_firmware_v1_0)) { + dev_err(adev->dev, + "gpu_info payload offset 0x%llx out of range (fw size %zu)\n", + (unsigned long long)off, + adev->firmware.gpu_info_fw->datasize); + err = -EINVAL; + goto out; + } + + gpu_info_fw = (const struct gpu_info_firmware_v1_0 *) + (adev->firmware.gpu_info_fw->data + off); - adev->gfx.config.max_shader_engines = le32_to_cpu(gpu_info_fw->gc_num_se); + /* DF-3698 family: consumers index fixed [4][4] arrays with these */ + adev->gfx.config.max_shader_engines = + min_t(u32, le32_to_cpu(gpu_info_fw->gc_num_se), 4); adev->gfx.config.max_cu_per_sh = le32_to_cpu(gpu_info_fw->gc_num_cu_per_sh); - adev->gfx.config.max_sh_per_se = le32_to_cpu(gpu_info_fw->gc_num_sh_per_se); + adev->gfx.config.max_sh_per_se = + min_t(u32, le32_to_cpu(gpu_info_fw->gc_num_sh_per_se), 4); adev->gfx.config.max_backends_per_se = le32_to_cpu(gpu_info_fw->gc_num_rb_per_se); adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gpu_info_fw->gc_num_tccs); |