diff --git a/sys/dev/drm/amd/amdgpu/gfx_v9_0.c b/sys/dev/drm/amd/amdgpu/gfx_v9_0.c --- a/sys/dev/drm/amd/amdgpu/gfx_v9_0.c +++ b/sys/dev/drm/amd/amdgpu/gfx_v9_0.c @@ -688,13 +688,43 @@ le32_to_cpu(rlc_hdr->reg_list_format_separate_start); adev->gfx.rlc.starting_offsets_start = le32_to_cpu(rlc_hdr->starting_offsets_start); + /* DF-1176: reg_list_format_size_bytes and reg_list_size_bytes are + * attacker-controlled u32 fields from the firmware header. Validate them + * against fw->datasize and compute the allocation size in size_t to + * prevent u32 wraparound -> undersized kmalloc -> heap overflow. + * Also validate reg_list_format_array_offset_bytes and + * reg_list_array_offset_bytes against fw->datasize to prevent OOB reads + * past the firmware buffer. */ adev->gfx.rlc.reg_list_format_size_bytes = le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); adev->gfx.rlc.reg_list_size_bytes = le32_to_cpu(rlc_hdr->reg_list_size_bytes); - 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); + + { + size_t rlf_sz = adev->gfx.rlc.reg_list_format_size_bytes; + size_t rl_sz = adev->gfx.rlc.reg_list_size_bytes; + size_t total = rlf_sz + rl_sz; + uint32_t rlf_off = le32_to_cpu( + rlc_hdr->reg_list_format_array_offset_bytes); + uint32_t rl_off = le32_to_cpu( + rlc_hdr->reg_list_array_offset_bytes); + size_t fw_ds = adev->gfx.rlc_fw->datasize; + + /* size_t overflow check */ + if (total < rlf_sz || + rlf_off > fw_ds || rlf_sz > fw_ds - rlf_off || + rl_off > fw_ds || rl_sz > fw_ds - rl_off) { + err = -EINVAL; + dev_err(adev->dev, + "invalid RLC reg_list sizes/off: fmt_sz=%u fmt_off=%u " + "list_sz=%u list_off=%u fw_ds=%zu\n", + adev->gfx.rlc.reg_list_format_size_bytes, rlf_off, + adev->gfx.rlc.reg_list_size_bytes, rl_off, fw_ds); + goto out; + } + adev->gfx.rlc.register_list_format = + kmalloc(total, M_DRM, GFP_KERNEL); + } if (!adev->gfx.rlc.register_list_format) { err = -ENOMEM; goto out;