DF-1164 / fix.diff
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c b/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c --- a/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c @@ -252,11 +252,30 @@ { const struct common_firmware_header *hdr = (const struct common_firmware_header *)fw->data; + uint32_t ucode_size; + uint32_t ucode_offset; - if (fw->datasize == le32_to_cpu(hdr->size_bytes)) - return 0; + /* The header itself must fit in the firmware blob. */ + if (fw->datasize < sizeof(*hdr)) + return -EINVAL; - return -EINVAL; + if (fw->datasize != le32_to_cpu(hdr->size_bytes)) + return -EINVAL; + + /* + * The declared ucode payload (offset + size) must lie entirely + * within the firmware blob. Without this check, a crafted header + * with an oversized ucode_size_bytes causes the CP/MEC/RLC/PFP/CE/ME + * loader loops in gfx_v7_0 (and similar) to read past the blob into + * adjacent kernel heap while writing to microcode RAM. + */ + ucode_size = le32_to_cpu(hdr->ucode_size_bytes); + ucode_offset = le32_to_cpu(hdr->ucode_array_offset_bytes); + if (ucode_offset > fw->datasize || + ucode_size > fw->datasize - ucode_offset) + return -EINVAL; + + return 0; } bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr, |