Commit 67bc09daa8fc ("drm/amd/display: Parse all extension blocks for VSDB")
changed the extension block parser from going over just one block to
reading up to as many blocks as specified in edid->extensions.
This is quite obviously broken because the loop directly above goes over
the extension blocks already and filters for the first DisplayID
extension block, so edid_ext might point to any random block, perhaps
even the very last block. Reading edid->extensions * EDID_LENGTH bytes
from here will almost certainly go out-of-bounds.
I suspect the intention was instead to look at all DisplayID blocks in
the EDID, which is what this patch implements.
This is not tagged with Cc: stable because AFAICS the offending commit
didn't make it to any stable PR yet.
Fixes: 67bc09daa8fc ("drm/amd/display: Parse all extension blocks for VSDB")
Signed-off-by: Natalie Vock <[email protected]>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 ++++++++++---------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 50a10b4fbb3ff..128a262068ec2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13093,7 +13093,6 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector
*aconnector,
u8 *edid_ext = NULL;
int i;
int j = 0;
- int total_ext_block_len;
if (edid == NULL || edid->extensions == 0)
return -ENODEV;
@@ -13101,17 +13100,21 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector
*aconnector,
/* Find DisplayID extension */
for (i = 0; i < edid->extensions; i++) {
edid_ext = (void *)(edid + (i + 1));
- if (edid_ext[0] == DISPLAYID_EXT)
- break;
- }
+ if (edid_ext[0] != DISPLAYID_EXT)
+ continue;
- total_ext_block_len = EDID_LENGTH * edid->extensions;
- while (j < total_ext_block_len - sizeof(struct amd_vsdb_block)) {
- struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block
*)&edid_ext[j];
- unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) |
(amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
+ j = 0;
+ while (j < EDID_LENGTH - sizeof(struct amd_vsdb_block)) {
+ struct amd_vsdb_block *amd_vsdb = (struct
amd_vsdb_block *)&edid_ext[j];
+ unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) |
(amd_vsdb->ieee_id[1] << 8) |
+ (amd_vsdb->ieee_id[0]);
+
+ if (ieeeId !=
HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID ||
+ amd_vsdb->version !=
HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) {
+ j++;
+ continue;
+ }
- if (ieeeId ==
HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID &&
- amd_vsdb->version ==
HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) {
u8 panel_type;
vsdb_info->replay_mode = (amd_vsdb->feature_caps &
AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false;
vsdb_info->amd_vsdb_version =
HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3;
@@ -13133,7 +13136,6 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector
*aconnector,
return true;
}
- j++;
}
return false;
--
2.53.0