DF-1133 / fix.diff
diff --git a/sys/dev/drm/amd/amdgpu/gfx_v8_0.c b/sys/dev/drm/amd/amdgpu/gfx_v8_0.c --- a/sys/dev/drm/amd/amdgpu/gfx_v8_0.c +++ b/sys/dev/drm/amd/amdgpu/gfx_v8_0.c @@ -1103,9 +1103,30 @@ adev->gfx.rlc.reg_list_size_bytes = le32_to_cpu(rlc_hdr->reg_list_size_bytes); + /* Both register-list sizes and the array offsets are read from + * the firmware header with no validation beyond + * amdgpu_ucode_validate() (which only checks datasize == + * size_bytes). Validate offset+size against the firmware blob + * to prevent OOB reads, and cast to size_t before adding so the + * kmalloc size cannot wrap (u32 + u32) into a tiny allocation. */ + { + u32 fmt_off = le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes); + u32 lst_off = le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes); + u32 dsize = adev->gfx.rlc_fw->datasize; + + if (fmt_off > dsize || + adev->gfx.rlc.reg_list_format_size_bytes > dsize - fmt_off || + lst_off > dsize || + adev->gfx.rlc.reg_list_size_bytes > dsize - lst_off) { + dev_err(adev->dev, "invalid RLC v2.0 register list sizes/offsets\n"); + err = -EINVAL; + goto out; + } + } + adev->gfx.rlc.register_list_format = - kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + - adev->gfx.rlc.reg_list_size_bytes, M_DRM, GFP_KERNEL); + kmalloc((size_t)adev->gfx.rlc.reg_list_format_size_bytes + + (size_t)adev->gfx.rlc.reg_list_size_bytes, M_DRM, GFP_KERNEL); if (!adev->gfx.rlc.register_list_format) { err = -ENOMEM; |