diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2013-10-29 13:31:36 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:23:07 -0700 |
| commit | 42c53b18dd85fe3251aabb836958befa8c59b953 (patch) | |
| tree | 51f9796a2d79dea915e4f441a4dc11f982080170 | |
| parent | 32d59d1eaab6d12e189ca16a172041fb382b6d44 (diff) | |
msm: mdss: hdmi: Proper length check for EDID data block
Check for the invalid length of EDID (Extended Display Identification
Data) data blocks while parsing the blocks. For a valid data block,
length should not be zero or should not exceed max size.
Change-Id: I4e83b07689d2c3161048efabbad35a0ad00e371a
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_edid.c | 86 |
1 files changed, 66 insertions, 20 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index d4f1b02131e9..39649404574d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -16,6 +16,13 @@ #include "mdss_hdmi_edid.h" #define DBC_START_OFFSET 4 + +/* + * As per CEA-861-E specification 7.5.2, there can be + * upto 31 bytes following any tag (data block type). + */ +#define MAX_DATA_BLOCK_SIZE 31 + #define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \ (!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13)) @@ -32,6 +39,17 @@ #define BUFF_SIZE_3D 128 +enum data_block_types { + RESERVED, + AUDIO_DATA_BLOCK, + VIDEO_DATA_BLOCK, + VENDOR_SPECIFIC_DATA_BLOCK, + SPEAKER_ALLOCATION_DATA_BLOCK, + VESA_DTC_DATA_BLOCK, + RESERVED2, + USE_EXTENDED_TAG +}; + struct hdmi_edid_sink_data { u32 disp_mode_list[HDMI_VFRMT_MAX]; u32 disp_3d_mode_list[HDMI_VFRMT_MAX]; @@ -526,7 +544,8 @@ static void hdmi_edid_extract_extended_data_blocks( } /* A Tage code of 7 identifies extended data blocks */ - etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len); + etag = hdmi_edid_find_block(in_buf, start_offset, USE_EXTENDED_TAG, + &len); while (etag != NULL) { /* The extended data block should at least be 2 bytes long */ @@ -572,7 +591,8 @@ static void hdmi_edid_extract_extended_data_blocks( /* There could be more that one extended data block */ start_offset = etag - in_buf + len + 1; - etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len); + etag = hdmi_edid_find_block(in_buf, start_offset, + USE_EXTENDED_TAG, &len); } } /* hdmi_edid_extract_extended_data_blocks */ @@ -587,11 +607,12 @@ static void hdmi_edid_extract_3d_present(struct hdmi_edid_ctrl *edid_ctrl, return; } - vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len); + vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + VENDOR_SPECIFIC_DATA_BLOCK, &len); edid_ctrl->present_3d = 0; - if (vsd == NULL || len < 9) { - DEV_DBG("%s: blk-id 3 not found or not long enough\n", + if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) { + DEV_DBG("%s: No/Invalid vendor Specific Data Block\n", __func__); return; } @@ -618,9 +639,13 @@ static void hdmi_edid_extract_audio_data_blocks( return; } - adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len); - if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE)) + adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, AUDIO_DATA_BLOCK, + &len); + if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE)) { + DEV_DBG("%s: No/Invalid Audio Data Block\n", + __func__); return; + } memcpy(edid_ctrl->audio_data_block, adb + 1, len); edid_ctrl->adb_size = len; @@ -646,9 +671,13 @@ static void hdmi_edid_extract_speaker_allocation_data( return; } - sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len); - if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) + sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + SPEAKER_ALLOCATION_DATA_BLOCK, &len); + if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) { + DEV_DBG("%s: No/Invalid Speaker Allocation Data Block\n", + __func__); return; + } memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len); edid_ctrl->sadb_size = len; @@ -675,9 +704,11 @@ static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl, return; } - vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len); + vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + VENDOR_SPECIFIC_DATA_BLOCK, &len); - if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) { + if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE || + !(vsd[8] & BIT(7))) { edid_ctrl->video_latency = (u16)-1; edid_ctrl->audio_latency = (u16)-1; DEV_DBG("%s: EDID: No audio/video latency present\n", __func__); @@ -701,9 +732,14 @@ static u32 hdmi_edid_extract_ieee_reg_id(struct hdmi_edid_ctrl *edid_ctrl, return 0; } - vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len); - if (vsd == NULL || len < 8) + vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + VENDOR_SPECIFIC_DATA_BLOCK, &len); + + if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) { + DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n", + __func__); return 0; + } DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__, ((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5); @@ -900,11 +936,14 @@ static int hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf, u16 structure_all, structure_mask; const u8 *vsd = num_of_cea_blocks ? hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, - 3, &len) : NULL; + VENDOR_SPECIFIC_DATA_BLOCK, &len) : NULL; int i; - if (!vsd) + if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) { + DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n", + __func__); return -ENXIO; + } offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd); if (offset >= len - 1) @@ -1046,10 +1085,11 @@ static void hdmi_edid_get_extended_video_formats( return; } - vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &db_len); + vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + VENDOR_SPECIFIC_DATA_BLOCK, &db_len); - if (vsd == NULL || db_len < 9) { - DEV_DBG("%s: blk-id 3 not found or not long enough\n", + if (vsd == NULL || db_len == 0 || db_len > MAX_DATA_BLOCK_SIZE) { + DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n", __func__); return; } @@ -1099,8 +1139,14 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl, edid_blk0 = &data_buf[0x0]; edid_blk1 = &data_buf[0x80]; svd = num_of_cea_blocks ? - hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2, - &len) : NULL; + hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, + VIDEO_DATA_BLOCK, &len) : NULL; + + if (svd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) { + DEV_DBG("%s: No/Invalid Video Data Block\n", + __func__); + return; + } sink_data = &edid_ctrl->sink_data; |
