DF-4289 / fix.diff
--- a/sys/dev/drm/amd/amdgpu/atom.h +++ b/sys/dev/drm/amd/amdgpu/atom.h @@ -126,6 +126,7 @@ struct atom_context { struct lock mutex; void *bios; + uint32_t bios_size; /* ROM image length in bytes */ uint32_t cmd_table, data_table; uint16_t *iio; @@ -146,7 +147,7 @@ struct atom_context { -struct atom_context *amdgpu_atom_parse(struct card_info *, void *); +struct atom_context *amdgpu_atom_parse(struct card_info *, void *, uint32_t); --- a/sys/dev/drm/amd/amdgpu/atom.c +++ b/sys/dev/drm/amd/amdgpu/atom.c @@ -1296,10 +1296,11 @@ -struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios) +struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios, + uint32_t bios_size) { int base; struct atom_context *ctx = kzalloc(sizeof(struct atom_context), GFP_KERNEL); @@ -1308,6 +1309,7 @@ ctx->card = card; ctx->bios = bios; + ctx->bios_size = bios_size; @@ -1384,9 +1386,19 @@ bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index, int offset = index * 2 + 4; int idx = CU16(ctx->data_table + offset); u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4); + uint16_t tsize; if (!mdt[index]) return false; + /* + * Security: idx and the table's own size field are VBIOS-controlled. + * Reject any data table whose declared extent runs past the end of + * the ROM image so downstream walkers (e.g. the fixed-stride + * ATOM_ASIC_SS_ASSIGNMENT walk in powerplay's + * asic_internal_ss_get_ss_asignment) cannot be steered out of the + * bios buffer by a crafted usStructureSize. + */ + tsize = CU16(idx); + if ((uint32_t)idx + tsize > ctx->bios_size) + return false; + if (size) *size = CU16(idx); --- a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c @@ -2034,7 +2034,8 @@ 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 = amdgpu_atom_parse(atom_card_info, + adev->bios, adev->bios_size); |