Merge "msm: mdss: hdmi: Proper length check for EDID data block"
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index cf0c287..5174cab 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/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,19 @@
 /* Support for first 5 EDID blocks */
 #define MAX_EDID_BLOCK_SIZE (0x80 * 5)
 
+#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];
@@ -524,7 +544,8 @@
 	}
 
 	/* 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 */
@@ -570,7 +591,8 @@
 
 		/* 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 */
 
@@ -585,11 +607,12 @@
 		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;
 	}
@@ -616,9 +639,13 @@
 		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;
@@ -644,9 +671,13 @@
 		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;
@@ -673,9 +704,11 @@
 		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__);
@@ -699,9 +732,14 @@
 		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);
@@ -898,11 +936,14 @@
 	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)
@@ -1044,10 +1085,11 @@
 		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;
 	}
@@ -1097,8 +1139,14 @@
 	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;