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

Commit 60085b54 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

msm: mdss: hdmi: Security check for EDID 3D data parsing



While parsing EDID (Extended display identification data) received
from TV for 3D data and other, proper buffer overflow check is done
to avoid data overflow or overwrite.
Also, replace snprintf with scnprintf for better memory copy results.

CRs-Fixed: 542823
Change-Id: I2603beea6eb88a92b013a1a45d960a4c3ba6c09b
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent 66619aa7
Loading
Loading
Loading
Loading
+30 −35
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
/* Support for first 5 EDID blocks */
#define MAX_EDID_BLOCK_SIZE (0x80 * 5)

#define BUFF_SIZE_3D 128

struct hdmi_edid_sink_data {
	u32 disp_mode_list[HDMI_VFRMT_MAX];
	u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -253,19 +255,19 @@ static ssize_t hdmi_edid_sysfs_rda_modes(struct device *dev,
			if (!hdmi_get_supported_mode(*video_mode))
				continue;
			if (ret > 0)
				ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
					*video_mode++);
				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
					",%d", *video_mode++);
			else
				ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
					*video_mode++);
				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
					"%d", *video_mode++);
		}
	} else {
		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d",
			edid_ctrl->video_resolution);
	}

	DEV_DBG("%s: '%s'\n", __func__, buf);
	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");

	return ret;
} /* hdmi_edid_sysfs_rda_modes */
@@ -283,7 +285,7 @@ static ssize_t hdmi_edid_sysfs_rda_physical_address(struct device *dev,
		return -EINVAL;
	}

	ret = snprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
	ret = scnprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
	DEV_DBG("%s: '%d'\n", __func__, edid_ctrl->physical_address);

	return ret;
@@ -302,7 +304,7 @@ static ssize_t hdmi_edid_sysfs_rda_scan_info(struct device *dev,
		return -EINVAL;
	}

	ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
	ret = scnprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
		edid_ctrl->it_scan_info, edid_ctrl->ce_scan_info);
	DEV_DBG("%s: '%s'\n", __func__, buf);

@@ -315,7 +317,8 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
{
	ssize_t ret = 0;
	int i;
	char buff_3d[128];
	char buff_3d[BUFF_SIZE_3D];

	struct hdmi_edid_ctrl *edid_ctrl =
		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);

@@ -331,23 +334,23 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,

		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
			ret = hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
				buff_3d);
				buff_3d, sizeof(buff_3d));
			if (ret > 0)
				ret += snprintf(buf+ret, PAGE_SIZE-ret,
				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
					",%d=%s", *video_mode++,
					buff_3d);
			else
				ret += snprintf(buf+ret, PAGE_SIZE-ret,
				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
					"%d=%s", *video_mode++,
					buff_3d);
		}
	} else {
		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d",
			edid_ctrl->video_resolution);
	}

	DEV_DBG("%s: '%s'\n", __func__, buf);
	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");

	return ret;
} /* hdmi_edid_sysfs_rda_3d_modes */
@@ -358,16 +361,18 @@ static ssize_t hdmi_common_rda_edid_raw_data(struct device *dev,
{
	struct hdmi_edid_ctrl *edid_ctrl =
		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
	u32 size = sizeof(edid_ctrl->edid_buf) < PAGE_SIZE ?
			sizeof(edid_ctrl->edid_buf) : PAGE_SIZE;

	if (!edid_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		return -EINVAL;
	}

	memcpy(buf, edid_ctrl->edid_buf,
		sizeof(edid_ctrl->edid_buf));
	/* buf can have max size of PAGE_SIZE */
	memcpy(buf, edid_ctrl->edid_buf, size);

	return sizeof(edid_ctrl->edid_buf);
	return size;
} /* hdmi_common_rda_edid_raw_data */
static DEVICE_ATTR(edid_raw_data, S_IRUGO, hdmi_common_rda_edid_raw_data, NULL);

@@ -839,7 +844,7 @@ static void hdmi_edid_detail_desc(const u8 *data_buf, u32 *disp_mode)
static void hdmi_edid_add_sink_3d_format(struct hdmi_edid_sink_data *sink_data,
	u32 video_format, u32 video_3d_format)
{
	char string[128];
	char string[BUFF_SIZE_3D];
	u32 added = false;
	int i;

@@ -851,7 +856,7 @@ static void hdmi_edid_add_sink_3d_format(struct hdmi_edid_sink_data *sink_data,
		}
	}

	hdmi_get_video_3d_fmt_2string(video_3d_format, string);
	hdmi_get_video_3d_fmt_2string(video_3d_format, string, sizeof(string));

	DEV_DBG("%s: EDID[3D]: format: %d [%s], %s %s\n", __func__,
		video_format, msm_hdmi_mode_2string(video_format),
@@ -1411,15 +1416,6 @@ int hdmi_edid_read(void *input)
	case 3:
	case 4:
		for (i = 1; i <= num_of_cea_blocks; i++) {
			if (!(i % 2)) {
				status = hdmi_edid_read_block(
					edid_ctrl, i, edid_buf + (0x80 * i));
				if (status) {
					DEV_ERR("%s: read blk(%d) failed:%d\n",
						__func__, i, status);
					goto error;
				}
			} else {
			status = hdmi_edid_read_block(
				edid_ctrl, i, edid_buf + (0x80 * i));
			if (status) {
@@ -1428,7 +1424,6 @@ int hdmi_edid_read(void *input)
				goto error;
			}
		}
		}
		break;
	default:
		DEV_ERR("%s: ddc read failed, not supported multi-blocks: %d\n",
+6 −6
Original line number Diff line number Diff line
@@ -123,30 +123,30 @@ const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
	return "";
} /* hdmi_get_single_video_3d_fmt_2string */

ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf)
ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size)
{
	ssize_t ret, len = 0;
	ret = snprintf(buf, PAGE_SIZE, "%s",
	ret = scnprintf(buf, size, "%s",
		hdmi_get_single_video_3d_fmt_2string(
			format & FRAME_PACKING));
	len += ret;

	if (len && (format & TOP_AND_BOTTOM))
		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
		ret = scnprintf(buf + len, size - len, ":%s",
			hdmi_get_single_video_3d_fmt_2string(
				format & TOP_AND_BOTTOM));
	else
		ret = snprintf(buf + len, PAGE_SIZE, "%s",
		ret = scnprintf(buf + len, size - len, "%s",
			hdmi_get_single_video_3d_fmt_2string(
				format & TOP_AND_BOTTOM));
	len += ret;

	if (len && (format & SIDE_BY_SIDE_HALF))
		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
		ret = scnprintf(buf + len, size - len, ":%s",
			hdmi_get_single_video_3d_fmt_2string(
				format & SIDE_BY_SIDE_HALF));
	else
		ret = snprintf(buf + len, PAGE_SIZE, "%s",
		ret = scnprintf(buf + len, size - len, "%s",
			hdmi_get_single_video_3d_fmt_2string(
				format & SIDE_BY_SIDE_HALF));
	len += ret;
+1 −1
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ void hdmi_setup_video_mode_lut(void);
int hdmi_get_video_id_code(struct msm_hdmi_mode_timing_info *timing_in);
const struct msm_hdmi_mode_timing_info *hdmi_get_supported_mode(u32 mode);
void hdmi_del_supported_mode(u32 mode);
ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size);

/* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);