DF-4862 / fix.diff
--- a/sys/dev/drm/amd/amdgpu/amdgpu_cgs.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_cgs.c @@ -212,6 +212,11 @@ struct amdgpu_firmware_info *ucode; id = fw_type_convert(cgs_device, type); + if (id >= AMDGPU_UCODE_ID_MAXIMUM) + /* fw_type_convert's default is exactly the array size: + * indexing ucode[id] reads one element past the end + * (ucode[MAXIMUM].fw aliases firmware.fw_buf). */ + return -EINVAL; ucode = &adev->firmware.ucode[id]; if (ucode->fw == NULL) return -EINVAL; @@ -231,8 +236,19 @@ info->mc_addr = gpu_addr; info->version = (uint16_t)le32_to_cpu(header->header.ucode_version); - if (CGS_UCODE_ID_CP_MEC == type) + if (CGS_UCODE_ID_CP_MEC == type) { + /* jt_offset is an unchecked header dword (up to ~4 GB + * after <<2). In a sane gfx header the JT payload + * lives inside the declared ucode image, so the window + * start must be <= ucode_size_bytes (== the staged copy + * size here). Unbounded, the SMU DMA engine + * (PPSMC_MSG_LoadUcodes via the smu7 TOC, + * entry->data_size_byte) reads far beyond the staged + * fw_buf window. */ + if (((uint64_t)le32_to_cpu(header->jt_offset) << 2) > data_size) + return -EINVAL; info->image_size = le32_to_cpu(header->jt_offset) << 2; + } info->fw_version = amdgpu_get_firmware_version(cgs_device, type); info->feature_version = (uint16_t)le32_to_cpu(header->ucode_feature_version); |