DF-1946 / 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,27 @@ { const struct common_firmware_header *hdr = (const struct common_firmware_header *)fw->data; + uint32_t size_bytes, ucode_size_bytes, ucode_array_offset_bytes; - if (fw->datasize == le32_to_cpu(hdr->size_bytes)) - return 0; + /* DF-1946: the buffer must be large enough to even contain the + * common header before we dereference any field of *hdr. */ + if (fw->datasize < sizeof(*hdr)) + return -EINVAL; - return -EINVAL; + size_bytes = le32_to_cpu(hdr->size_bytes); + ucode_size_bytes = le32_to_cpu(hdr->ucode_size_bytes); + ucode_array_offset_bytes = le32_to_cpu(hdr->ucode_array_offset_bytes); + + if (fw->datasize != size_bytes) + return -EINVAL; + + /* The declared payload must lie entirely within the firmware image. + * Performed in 64-bit to avoid offset+size wrap-around. */ + if ((uint64_t)ucode_array_offset_bytes + (uint64_t)ucode_size_bytes > + (uint64_t)size_bytes) + return -EINVAL; + + return 0; } bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr, |