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

Commit cfb838fd authored by Dhaval Patel's avatar Dhaval Patel Committed by Krishna Manikandan
Browse files

drm/msm/sde: remove out of bound access for qos lut parsing



QOS LUT dtsi entries use existing hardware parsing APIs
but dos not increase the size of array. This causes out of
bound access while reading u32 lut array entry. This patch
fixes the array size and also adds checks to avoid future
out of bound access. It also fixes the memory leak in
qos lut parsing.

Change-Id: I98de052d03e1bcfd79d15ab99ca41d7782e56682
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
Signed-off-by: default avatarAbhinav Kumar <abhinavk@codeaurora.org>
parent fb2dcac5
Loading
Loading
Loading
Loading
+67 −25
Original line number Diff line number Diff line
@@ -27,11 +27,11 @@

/**
 * Max hardware block in certain hardware. For ex: sspp pipes
 * can have QSEED, pcc, igc, pa, csc, etc. This count is max
 * 12 based on software design. It should be increased if any of the
 * can have QSEED, pcc, igc, pa, csc, qos entries, etc. This count is
 * 64 based on software design. It should be increased if any of the
 * hardware block has more subblocks.
 */
#define MAX_SDE_HW_BLK  12
#define MAX_SDE_HW_BLK  64

/* each entry will have register address and bit offset in that register */
#define MAX_BIT_OFFSET 2
@@ -444,8 +444,16 @@ static uint32_t _sde_copy_formats(
static int _parse_dt_u32_handler(struct device_node *np,
	char *prop_name, u32 *offsets, int len, bool mandatory)
{
	int rc = of_property_read_u32_array(np, prop_name, offsets, len);
	int rc = -EINVAL;

	if (len > MAX_SDE_HW_BLK) {
		SDE_ERROR(
			"prop: %s tries out of bound access for u32 array read len: %d\n",
				prop_name, len);
		return -E2BIG;
	}

	rc = of_property_read_u32_array(np, prop_name, offsets, len);
	if (rc && mandatory)
		SDE_ERROR("mandatory prop: %s u32 array read len:%d\n",
				prop_name, len);
@@ -467,6 +475,14 @@ static int _parse_dt_bit_offset(struct device_node *np,
	if (arr) {
		len /= sizeof(u32);
		len &= ~0x1;

		if (len > (MAX_SDE_HW_BLK * MAX_BIT_OFFSET)) {
			SDE_ERROR(
				"prop: %s len: %d will lead to out of bound access\n",
				prop_name, len / MAX_BIT_OFFSET);
			return -E2BIG;
		}

		for (i = 0, j = 0; i < len; j++) {
			PROP_BITVALUE_ACCESS(prop_value, prop_index, j, 0) =
				be32_to_cpu(arr[i]);
@@ -501,8 +517,8 @@ static int _validate_dt_entry(struct device_node *np,
				sde_prop[0].prop_name);
		if ((*off_count > MAX_BLOCKS) || (*off_count < 0)) {
			if (sde_prop[0].is_mandatory) {
				SDE_ERROR("invalid hw offset prop name:%s\"\
					  count: %d\n",
				SDE_ERROR(
					"invalid hw offset prop name:%s count: %d\n",
					sde_prop[0].prop_name, *off_count);
				rc = -EINVAL;
			}
@@ -545,8 +561,9 @@ static int _validate_dt_entry(struct device_node *np,
							sde_prop[i].type);
			break;
		}
		SDE_DEBUG("prop id:%d prop name:%s prop type:%d \"\
			prop_count:%d\n", i, sde_prop[i].prop_name,
		SDE_DEBUG(
			"prop id:%d prop name:%s prop type:%d prop_count:%d\n",
			i, sde_prop[i].prop_name,
			sde_prop[i].type, prop_count[i]);

		if (rc && sde_prop[i].is_mandatory &&
@@ -564,14 +581,16 @@ static int _validate_dt_entry(struct device_node *np,

		if (off_count && (prop_count[i] != *off_count) &&
				sde_prop[i].is_mandatory) {
			SDE_ERROR("prop:%s count:%d is different compared to \"\
				offset array:%d\n", sde_prop[i].prop_name,
			SDE_ERROR(
				"prop:%s count:%d is different compared to offset array:%d\n",
				sde_prop[i].prop_name,
				prop_count[i], *off_count);
			rc = -EINVAL;
			goto end;
		} else if (off_count && prop_count[i] != *off_count) {
			SDE_DEBUG("prop:%s count:%d is different compared to \"\
				offset array:%d\n", sde_prop[i].prop_name,
			SDE_DEBUG(
				"prop:%s count:%d is different compared to offset array:%d\n",
				sde_prop[i].prop_name,
				prop_count[i], *off_count);
			rc = 0;
			prop_count[i] = 0;
@@ -607,8 +626,9 @@ static int _read_dt_entry(struct device_node *np,
		case PROP_TYPE_U32:
			rc = of_property_read_u32(np, sde_prop[i].prop_name,
				&PROP_VALUE_ACCESS(prop_value, i, 0));
			SDE_DEBUG("prop id:%d prop name:%s prop type:%d \"\
				 value:0x%x\n", i, sde_prop[i].prop_name,
			SDE_DEBUG(
				"prop id:%d prop name:%s prop type:%d value:0x%x\n",
				i, sde_prop[i].prop_name,
				sde_prop[i].type,
				PROP_VALUE_ACCESS(prop_value, i, 0));
			if (rc)
@@ -618,8 +638,9 @@ static int _read_dt_entry(struct device_node *np,
			PROP_VALUE_ACCESS(prop_value, i, 0) =
				of_property_read_bool(np,
					sde_prop[i].prop_name);
			SDE_DEBUG("prop id:%d prop name:%s prop type:%d \"\
				value:0x%x\n", i, sde_prop[i].prop_name,
			SDE_DEBUG(
				"prop id:%d prop name:%s prop type:%d value:0x%x\n",
				i, sde_prop[i].prop_name,
				sde_prop[i].type,
				PROP_VALUE_ACCESS(prop_value, i, 0));
			break;
@@ -628,8 +649,9 @@ static int _read_dt_entry(struct device_node *np,
				&PROP_VALUE_ACCESS(prop_value, i, 0),
				prop_count[i], sde_prop[i].is_mandatory);
			if (rc && sde_prop[i].is_mandatory) {
				SDE_ERROR("%s prop validation success but \"\
					read failed\n", sde_prop[i].prop_name);
				SDE_ERROR(
					"%s prop validation success but read failed\n",
					sde_prop[i].prop_name);
				prop_exists[i] = false;
				goto end;
			} else {
@@ -651,19 +673,21 @@ static int _read_dt_entry(struct device_node *np,
				prop_value, i, prop_count[i],
				sde_prop[i].is_mandatory);
			if (rc && sde_prop[i].is_mandatory) {
				SDE_ERROR("%s prop validation success but \"\
					read failed\n", sde_prop[i].prop_name);
				SDE_ERROR(
					"%s prop validation success but read failed\n",
					sde_prop[i].prop_name);
				prop_exists[i] = false;
				goto end;
			} else {
				if (rc)
					prop_exists[i] = false;
				SDE_DEBUG("prop id:%d prop name:%s prop \"\
					type:%d", i, sde_prop[i].prop_name,
				SDE_DEBUG(
					"prop id:%d prop name:%s prop type:%d",
					i, sde_prop[i].prop_name,
					sde_prop[i].type);
				for (j = 0; j < prop_count[i]; j++)
					SDE_DEBUG(" count[%d]: bit:0x%x \"\
					off:0x%x \n", j,
					SDE_DEBUG(
					"count[%d]: bit:0x%x off:0x%x\n", j,
					PROP_BITVALUE_ACCESS(prop_value,
						i, j, 0),
					PROP_BITVALUE_ACCESS(prop_value,
@@ -979,6 +1003,16 @@ static int sde_sspp_parse_dt(struct device_node *np,
			goto end;
		}

		snprintf(sblk->src_blk.name, SDE_HW_BLK_NAME_LEN, "sspp_src_%u",
				sspp->id - SSPP_VIG0);

		if (sspp->clk_ctrl >= SDE_CLK_CTRL_MAX) {
			SDE_ERROR("%s: invalid clk ctrl: %d\n",
					sblk->src_blk.name, sspp->clk_ctrl);
			rc = -EINVAL;
			goto end;
		}

		sblk->maxhdeciexp = MAX_HORZ_DECIMATION;
		sblk->maxvdeciexp = MAX_VERT_DECIMATION;

@@ -1336,6 +1370,14 @@ static int sde_wb_parse_dt(struct device_node *np,
			PROP_VALUE_ACCESS(prop_value, WB_ID, i);
		wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i);
		wb->vbif_idx = VBIF_NRT;

		if (wb->clk_ctrl >= SDE_CLK_CTRL_MAX) {
			SDE_ERROR("%s: invalid clk ctrl: %d\n",
					wb->name, wb->clk_ctrl);
			rc = -EINVAL;
			goto end;
		}

		wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0);
		wb->format_list = wb2_formats;
		if (!prop_exists[WB_LEN])
@@ -2052,7 +2094,7 @@ static int sde_perf_parse_dt(struct device_node *np,
		goto end;
	}

	prop_value = kzalloc(SDE_PROP_MAX *
	prop_value = kzalloc(PERF_PROP_MAX *
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!prop_value) {
		rc = -ENOMEM;