Bladeren bron

msm: camera: utils: Add address validation for io operation

Kernel panic might be caused by improper register offset which
is not memory aligned during write or read operation, this change
adds a validation for the offset to avoid accessing invalid address.

CRs-Fixed: 3542219
Change-Id: I8761c8d416890bd4571be8a64118036c0173d303
Signed-off-by: Stark Lin <[email protected]>
Stark Lin 1 jaar geleden
bovenliggende
commit
56429494cb
2 gewijzigde bestanden met toevoegingen van 108 en 98 verwijderingen
  1. 46 92
      drivers/cam_utils/cam_soc_util.c
  2. 62 6
      drivers/cam_utils/cam_soc_util.h

+ 46 - 92
drivers/cam_utils/cam_soc_util.c

@@ -3499,7 +3499,7 @@ static int cam_soc_util_dump_cont_reg_range(
 	struct cam_reg_range_read_desc *reg_read, uint32_t base_idx,
 	struct cam_reg_dump_out_buffer *dump_out_buf, uintptr_t cmd_buf_end)
 {
-	int         i = 0, rc = 0;
+	int         i = 0, rc = 0, val = 0;
 	uint32_t    write_idx = 0;
 
 	if (!soc_info || !dump_out_buf || !reg_read || !cmd_buf_end) {
@@ -3536,21 +3536,14 @@ static int cam_soc_util_dump_cont_reg_range(
 
 	write_idx = dump_out_buf->bytes_written / sizeof(uint32_t);
 	for (i = 0; i < reg_read->num_values; i++) {
-		if ((reg_read->offset + (i * sizeof(uint32_t))) >
-			(uint32_t)soc_info->reg_map[base_idx].size) {
-			CAM_ERR(CAM_UTIL,
-				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-				(reg_read->offset + (i * sizeof(uint32_t))),
-				(uint32_t)soc_info->reg_map[base_idx].size);
-			rc = -EINVAL;
-			goto end;
-		}
+		val = cam_soc_util_r(soc_info, base_idx,
+			(reg_read->offset + (i * sizeof(uint32_t))));
+		if (!val)
+			CAM_WARN(CAM_UTIL, "Possibly fails to read");
 
 		dump_out_buf->dump_data[write_idx++] = reg_read->offset +
 			(i * sizeof(uint32_t));
-		dump_out_buf->dump_data[write_idx++] =
-			cam_soc_util_r(soc_info, base_idx,
-			(reg_read->offset + (i * sizeof(uint32_t))));
+		dump_out_buf->dump_data[write_idx++] = val;
 		dump_out_buf->bytes_written += (2 * sizeof(uint32_t));
 	}
 
@@ -3563,7 +3556,7 @@ static int cam_soc_util_dump_dmi_reg_range(
 	struct cam_dmi_read_desc *dmi_read, uint32_t base_idx,
 	struct cam_reg_dump_out_buffer *dump_out_buf, uintptr_t cmd_buf_end)
 {
-	int        i = 0, rc = 0;
+	int        i = 0, rc = 0, val = 0;
 	uint32_t   write_idx = 0;
 
 	if (!soc_info || !dump_out_buf || !dmi_read || !cmd_buf_end) {
@@ -3618,19 +3611,14 @@ static int cam_soc_util_dump_dmi_reg_range(
 
 	write_idx = dump_out_buf->bytes_written / sizeof(uint32_t);
 	for (i = 0; i < dmi_read->num_pre_writes; i++) {
-		if (dmi_read->pre_read_config[i].offset >
-			(uint32_t)soc_info->reg_map[base_idx].size) {
-			CAM_ERR(CAM_UTIL,
-				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-				dmi_read->pre_read_config[i].offset,
-				(uint32_t)soc_info->reg_map[base_idx].size);
-			rc = -EINVAL;
+		rc = cam_soc_util_w_mb(soc_info, base_idx,
+			dmi_read->pre_read_config[i].offset,
+			dmi_read->pre_read_config[i].value);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Fails to write for pre_read_config");
 			goto end;
 		}
 
-		cam_soc_util_w_mb(soc_info, base_idx,
-			dmi_read->pre_read_config[i].offset,
-			dmi_read->pre_read_config[i].value);
 		dump_out_buf->dump_data[write_idx++] =
 			dmi_read->pre_read_config[i].offset;
 		dump_out_buf->dump_data[write_idx++] =
@@ -3638,39 +3626,26 @@ static int cam_soc_util_dump_dmi_reg_range(
 		dump_out_buf->bytes_written += (2 * sizeof(uint32_t));
 	}
 
-	if (dmi_read->dmi_data_read.offset >
-		(uint32_t)soc_info->reg_map[base_idx].size) {
-		CAM_ERR(CAM_UTIL,
-			"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-			dmi_read->dmi_data_read.offset,
-			(uint32_t)soc_info->reg_map[base_idx].size);
-		rc = -EINVAL;
-		goto end;
-	}
-
 	for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) {
+		val = cam_soc_util_r_mb(soc_info, base_idx,
+			dmi_read->dmi_data_read.offset);
+		if (!val)
+			CAM_WARN(CAM_UTIL, "Possibly fails to read for dmi_data_read");
+
 		dump_out_buf->dump_data[write_idx++] =
 			dmi_read->dmi_data_read.offset;
-		dump_out_buf->dump_data[write_idx++] =
-			cam_soc_util_r_mb(soc_info, base_idx,
-			dmi_read->dmi_data_read.offset);
+		dump_out_buf->dump_data[write_idx++] = val;
 		dump_out_buf->bytes_written += (2 * sizeof(uint32_t));
 	}
 
 	for (i = 0; i < dmi_read->num_post_writes; i++) {
-		if (dmi_read->post_read_config[i].offset >
-			(uint32_t)soc_info->reg_map[base_idx].size) {
-			CAM_ERR(CAM_UTIL,
-				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-				dmi_read->post_read_config[i].offset,
-				(uint32_t)soc_info->reg_map[base_idx].size);
-			rc = -EINVAL;
-			goto end;
-		}
-
-		cam_soc_util_w_mb(soc_info, base_idx,
+		rc = cam_soc_util_w_mb(soc_info, base_idx,
 			dmi_read->post_read_config[i].offset,
 			dmi_read->post_read_config[i].value);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Fails to write for post_read_config");
+			goto end;
+		}
 	}
 
 end:
@@ -3684,6 +3659,7 @@ static int cam_soc_util_dump_dmi_reg_range_user_buf(
 {
 	int                            i;
 	int                            rc;
+	int                            val = 0;
 	size_t                         buf_len = 0;
 	uint8_t                       *dst;
 	size_t                         remain_len;
@@ -3745,52 +3721,36 @@ static int cam_soc_util_dump_dmi_reg_range_user_buf(
 	*waddr = soc_info->index;
 	waddr++;
 	for (i = 0; i < dmi_read->num_pre_writes; i++) {
-		if (dmi_read->pre_read_config[i].offset >
-			(uint32_t)soc_info->reg_map[base_idx].size) {
-			CAM_ERR(CAM_UTIL,
-				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-				dmi_read->pre_read_config[i].offset,
-				(uint32_t)soc_info->reg_map[base_idx].size);
-			rc = -EINVAL;
+		rc = cam_soc_util_w_mb(soc_info, base_idx,
+			dmi_read->pre_read_config[i].offset,
+			dmi_read->pre_read_config[i].value);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Fails to write for pre_read_config");
 			goto end;
 		}
 
-		cam_soc_util_w_mb(soc_info, base_idx,
-			dmi_read->pre_read_config[i].offset,
-			dmi_read->pre_read_config[i].value);
 		*waddr++ = dmi_read->pre_read_config[i].offset;
 		*waddr++ = dmi_read->pre_read_config[i].value;
 	}
 
-	if (dmi_read->dmi_data_read.offset >
-		(uint32_t)soc_info->reg_map[base_idx].size) {
-		CAM_ERR(CAM_UTIL,
-			"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-			dmi_read->dmi_data_read.offset,
-			(uint32_t)soc_info->reg_map[base_idx].size);
-		rc = -EINVAL;
-		goto end;
-	}
-
 	for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) {
-		*waddr++ = dmi_read->dmi_data_read.offset;
-		*waddr++ = cam_soc_util_r_mb(soc_info, base_idx,
+		val = cam_soc_util_r_mb(soc_info, base_idx,
 			dmi_read->dmi_data_read.offset);
+		if (!val)
+			CAM_WARN(CAM_UTIL, "Possibly fails to read for dmi_data_read");
+
+		*waddr++ = dmi_read->dmi_data_read.offset;
+		*waddr++ = val;
 	}
 
 	for (i = 0; i < dmi_read->num_post_writes; i++) {
-		if (dmi_read->post_read_config[i].offset >
-			(uint32_t)soc_info->reg_map[base_idx].size) {
-			CAM_ERR(CAM_UTIL,
-				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-				dmi_read->post_read_config[i].offset,
-				(uint32_t)soc_info->reg_map[base_idx].size);
-			rc = -EINVAL;
-			goto end;
-		}
-		cam_soc_util_w_mb(soc_info, base_idx,
+		rc = cam_soc_util_w_mb(soc_info, base_idx,
 			dmi_read->post_read_config[i].offset,
 			dmi_read->post_read_config[i].value);
+		if (rc) {
+			CAM_ERR(CAM_UTIL, "Fails to write for post_read_config");
+			goto end;
+		}
 	}
 	hdr->size = (waddr - start) * hdr->word_size;
 	dump_args->offset +=  hdr->size +
@@ -3808,7 +3768,7 @@ static int cam_soc_util_dump_cont_reg_range_user_buf(
 	struct cam_hw_soc_dump_args *dump_args)
 {
 	int                            i;
-	int                            rc = 0;
+	int                            rc = 0, val = 0;
 	size_t                         buf_len;
 	uint8_t                       *dst;
 	size_t                         remain_len;
@@ -3859,19 +3819,13 @@ static int cam_soc_util_dump_cont_reg_range_user_buf(
 	*waddr = soc_info->index;
 	waddr++;
 	for (i = 0; i < reg_read->num_values; i++) {
-		if ((reg_read->offset + (i * sizeof(uint32_t))) >
-			(uint32_t)soc_info->reg_map[base_idx].size) {
-			CAM_ERR(CAM_UTIL,
-				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
-				(reg_read->offset + (i * sizeof(uint32_t))),
-				(uint32_t)soc_info->reg_map[base_idx].size);
-			rc = -EINVAL;
-			goto end;
-		}
+		val = cam_soc_util_r(soc_info, base_idx,
+			(reg_read->offset + (i * sizeof(uint32_t))));
+		if (!val)
+			CAM_WARN(CAM_UTIL, "Possibly fails to read");
 
 		waddr[0] = reg_read->offset + (i * sizeof(uint32_t));
-		waddr[1] = cam_soc_util_r(soc_info, base_idx,
-			(reg_read->offset + (i * sizeof(uint32_t))));
+		waddr[1] = val;
 		waddr += 2;
 	}
 	hdr->size = (waddr - start) * hdr->word_size;

+ 62 - 6
drivers/cam_utils/cam_soc_util.h

@@ -21,6 +21,7 @@
 #include <linux/of_fdt.h>
 
 #include "cam_io_util.h"
+#include "cam_debug_util.h"
 #include <media/cam_defs.h>
 
 #if IS_REACHABLE(CONFIG_MSM_MMRM)
@@ -666,6 +667,37 @@ int cam_soc_util_regulator_disable(struct regulator *rgltr,
 	uint32_t rgltr_min_volt, uint32_t rgltr_max_volt,
 	uint32_t rgltr_op_mode, uint32_t rgltr_delay);
 
+/**
+ * cam_soc_util_reg_addr_validation()
+ *
+ * @brief:              Camera SOC util for validating address to be accessed
+ *
+ * @soc_info:           Device soc information
+ * @base_index:         Index of register space in the HW block
+ * @offset:             Register offset
+ *
+ * @return:             0 or specific error code
+ */
+static inline int cam_soc_util_reg_addr_validation(
+	struct cam_hw_soc_info *soc_info,
+	uint32_t base_idx, uint32_t offset)
+{
+	if (offset > (uint32_t)soc_info->reg_map[base_idx].size) {
+		CAM_ERR(CAM_UTIL,
+			"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
+			offset,
+			(uint32_t)soc_info->reg_map[base_idx].size);
+		return -EINVAL;
+	}
+
+	if (offset % 4) {
+		CAM_ERR(CAM_UTIL, "Offset: 0x%X is not memory aligned",
+			offset);
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
 /**
  * cam_soc_util_w()
@@ -674,7 +706,7 @@ int cam_soc_util_regulator_disable(struct regulator *rgltr,
  *
  * @soc_info:           Device soc information
  * @base_index:         Index of register space in the HW block
- * @offset:             Offset of register to be read
+ * @offset:             Offset of register to be writen
  * @data:               Value to be written
  *
  * @return:             Success or Failure
@@ -682,8 +714,14 @@ int cam_soc_util_regulator_disable(struct regulator *rgltr,
 static inline int cam_soc_util_w(struct cam_hw_soc_info *soc_info,
 	uint32_t base_index, uint32_t offset, uint32_t data)
 {
-	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
+	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) {
+		CAM_ERR(CAM_UTIL, "No valid mapped starting address found");
 		return -EINVAL;
+	}
+
+	if (cam_soc_util_reg_addr_validation(soc_info, base_index, offset))
+		return -EINVAL;
+
 	return cam_io_w(data,
 		CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
 }
@@ -698,7 +736,7 @@ static inline int cam_soc_util_w(struct cam_hw_soc_info *soc_info,
  *
  * @soc_info:           Device soc information
  * @base_index:         Index of register space in the HW block
- * @offset:             Offset of register to be read
+ * @offset:             Offset of register to be writen
  * @data:               Value to be written
  *
  * @return:             Success or Failure
@@ -706,8 +744,14 @@ static inline int cam_soc_util_w(struct cam_hw_soc_info *soc_info,
 static inline int cam_soc_util_w_mb(struct cam_hw_soc_info *soc_info,
 	uint32_t base_index, uint32_t offset, uint32_t data)
 {
-	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
+	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) {
+		CAM_ERR(CAM_UTIL, "No valid mapped starting address found");
 		return -EINVAL;
+	}
+
+	if (cam_soc_util_reg_addr_validation(soc_info, base_index, offset))
+		return -EINVAL;
+
 	return cam_io_w_mb(data,
 		CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
 }
@@ -726,8 +770,14 @@ static inline int cam_soc_util_w_mb(struct cam_hw_soc_info *soc_info,
 static inline uint32_t cam_soc_util_r(struct cam_hw_soc_info *soc_info,
 	uint32_t base_index, uint32_t offset)
 {
-	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
+	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) {
+		CAM_ERR(CAM_UTIL, "No valid mapped starting address found");
 		return 0;
+	}
+
+	if (cam_soc_util_reg_addr_validation(soc_info, base_index, offset))
+		return 0;
+
 	return cam_io_r(
 		CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
 }
@@ -749,8 +799,14 @@ static inline uint32_t cam_soc_util_r(struct cam_hw_soc_info *soc_info,
 static inline uint32_t cam_soc_util_r_mb(struct cam_hw_soc_info *soc_info,
 	uint32_t base_index, uint32_t offset)
 {
-	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
+	if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) {
+		CAM_ERR(CAM_UTIL, "No valid mapped starting address found");
 		return 0;
+	}
+
+	if (cam_soc_util_reg_addr_validation(soc_info, base_index, offset))
+		return 0;
+
 	return cam_io_r_mb(
 		CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
 }