drm_parse_tiled_block() casts the generic DisplayID data block to struct displayid_tiled_block and unconditionally reads the whole fixed-size structure (tile_cap, topo[3], tile_size[4], tile_pixel_bezel[5] and the 8-byte topology_id), but it never looks at block->num_bytes.
The DisplayID iterator in displayid_iter_block() only guarantees that the block's *declared* length, sizeof(struct displayid_block) + num_bytes, fits inside the section. A DisplayID extension that declares a tiled display block (tag DATA_BLOCK_TILED_DISPLAY) with a num_bytes smaller than the structure payload is therefore happily handed to the parser, which then reads past the declared block. When such a block is placed near the end of the last DisplayID EDID extension, the over-read runs past the end of the EDID allocation - an out-of-bounds read controlled entirely by the contents of the EDID. Reject tiled blocks that are too short to hold the structure, mirroring the size check already done for the VESA vendor block in drm_parse_vesa_mso_data(). Signed-off-by: Naveed Khan <[email protected]> --- diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 404208bf23..b4298012eb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -7575,6 +7575,13 @@ static void drm_parse_tiled_block(struct drm_connector *connector, u8 num_v_tile, num_h_tile; struct drm_tile_group *tg; + if (block->num_bytes < sizeof(*tile) - sizeof(*block)) { + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Invalid tiled display block size %u\n", + connector->base.id, connector->name, block->num_bytes); + return; + } + w = tile->tile_size[0] | tile->tile_size[1] << 8; h = tile->tile_size[2] | tile->tile_size[3] << 8; -- 2.52.0
