DF-4104 / fix.diff
--- a/sys/dev/drm/amd/amdgpu/atom.h +++ b/sys/dev/drm/amd/amdgpu/atom.h @@ -129,6 +129,7 @@ struct atom_context { struct lock mutex; void *bios; + int bios_size; uint32_t cmd_table, data_table; uint16_t *iio; --- a/sys/dev/drm/amd/amdgpu/atom.c +++ b/sys/dev/drm/amd/amdgpu/atom.c @@ -1314,6 +1314,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios) ctx->card = card; ctx->bios = bios; + ctx->bios_size = 0; /* caller patches via amdgpu_atom_parse_bios_size */ base = CU16(ATOM_ROM_TABLE_PTR); @@ -1384,9 +1385,16 @@ bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index, if (size) *size = CU16(idx); if (frev) *frev = CU8(idx + 2); if (crev) *crev = CU8(idx + 3); + /* + * The table header itself must lie inside the BIOS image; + * consumers additionally validate data_start + sizeof(struct). + */ + if (ctx->bios_size && idx + 4 > ctx->bios_size) + return false; *data_start = idx; return true; } + +void amdgpu_atom_parse_bios_size(struct atom_context *ctx, int size) +{ + ctx->bios_size = size; +} --- a/sys/dev/drm/amd/amdgpu/atombios_encoders.c +++ b/sys/dev/drm/amd/amdgpu/atombios_encoders.c @@ -2081,7 +2081,9 @@ amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder) if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { + if (mode_info->atom_context->bios_size && + (int)data_offset + sizeof(union lvds_info) > + mode_info->atom_context->bios_size) + return NULL; lvds_info = (union lvds_info *)(mode_info->atom_context->bios + data_offset); --- a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c @@ -2037,6 +2037,8 @@ int amdgpu_atombios_init(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios); + amdgpu_atom_parse_bios_size(adev->mode_info.atom_context, + adev->bios_size); if (!adev->mode_info.atom_context) { kfree(atom_card_info); return -ENOMEM; |