Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05b9885c authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: hdmi: Proper length check for EDID data block"

parents 23083778 09e970d0
Loading
Loading
Loading
Loading
+66 −20
Original line number Diff line number Diff line
@@ -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;