diff --git a/sys/dev/drm/amd/amdgpu/atom.h b/sys/dev/drm/amd/amdgpu/atom.h index 1111111..2222222 100644 @@ -127,6 +127,7 @@ struct card_info *card; struct lock mutex; void *bios; + uint32_t bios_size; uint32_t cmd_table, data_table; uint16_t *iio; diff --git a/sys/dev/drm/amd/amdgpu/atom.c b/sys/dev/drm/amd/amdgpu/atom.c index 3333333..4444444 100644 @@ -1306,6 +1306,7 @@ ctx->card = card; ctx->bios = bios; + ctx->bios_size = 0; if (CU16(0) != ATOM_BIOS_MAGIC) { pr_info("Invalid BIOS magic\n"); @@ -1392,8 +1393,25 @@ if (!mdt[index]) return false; - if (size) - *size = CU16(idx); + /* + * idx (and the data table it points at) is read directly from the VBIOS + * image and is therefore attacker-controlled. Validate that the whole + * table -- including its size/frev/crev header -- lies within the BIOS + * image before returning it, so callers that dereference + * (ctx->bios + idx) cannot read past the kmalloc'd VBIOS buffer. + * ctx->bios_size of 0 means unknown (legacy callers): skip the check. + */ + { + uint16_t tbl_size = CU16(idx); + + if (ctx->bios_size && + ((uint32_t)idx + 4 > ctx->bios_size || + (uint32_t)idx + tbl_size > ctx->bios_size)) + return false; + if (size) + *size = tbl_size; + } + if (frev) *frev = CU8(idx + 2); if (crev) diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c index 5555555..6666666 100644 @@ -2035,6 +2035,7 @@ atom_card_info->pll_write = cail_pll_write; adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios); + adev->mode_info.atom_context->bios_size = adev->bios_size; if (!adev->mode_info.atom_context) { amdgpu_atombios_fini(adev); return -ENOMEM;