From f615e40c706708f74cd826d5b19c63025f54c041 Mon Sep 17 00:00:00 2001 From: Seemanta Dutta Date: Tue, 23 Jul 2013 15:52:22 -0700 Subject: msm: camera: Fix potential memory overflow errors Fix potential memory overflow errors in msm_isp_util.c which happen under certain rare conditions. CRs-fixed: 514717 Change-Id: I8c70e089df9bf1e7a364c5c8264b782c9c23bf0b Signed-off-by: Seemanta Dutta --- .../platform/msm/camera_v2/isp/msm_isp_util.c | 47 +++++++++++++++++++--- .../platform/msm/camera_v2/isp/msm_isp_util.h | 2 +- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 3806213..9b9c5a3 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -366,7 +366,7 @@ long msm_isp_ioctl(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_SET_SRC_STATE: mutex_lock(&vfe_dev->core_mutex); - msm_isp_set_src_state(vfe_dev, arg); + rc = msm_isp_set_src_state(vfe_dev, arg); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: @@ -410,7 +410,7 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, if (resource_size(vfe_dev->vfe_mem) < (reg_cfg_cmd->u.rw_info.reg_offset + reg_cfg_cmd->u.rw_info.len)) { - pr_err("%s: Invalid length\n", __func__); + pr_err("%s: VFE_WRITE: Invalid length\n", __func__); return -EINVAL; } msm_camera_io_memcpy(vfe_dev->vfe_base + @@ -422,16 +422,37 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, case VFE_WRITE_MB: { uint32_t *data_ptr = cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4; + + if ((UINT_MAX - sizeof(*data_ptr) < + reg_cfg_cmd->u.rw_info.reg_offset) || + (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.rw_info.reg_offset + + sizeof(*data_ptr))) { + pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__); + return -EINVAL; + } msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base + reg_cfg_cmd->u.rw_info.reg_offset); break; } case VFE_CFG_MASK: { uint32_t temp; + if (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.mask_info.reg_offset) + return -EINVAL; temp = msm_camera_io_r(vfe_dev->vfe_base + reg_cfg_cmd->u.mask_info.reg_offset); + temp &= ~reg_cfg_cmd->u.mask_info.mask; temp |= reg_cfg_cmd->u.mask_info.val; + if ((UINT_MAX - sizeof(temp) < + reg_cfg_cmd->u.mask_info.reg_offset) || + (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.mask_info.reg_offset + + sizeof(temp))) { + pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__); + return -EINVAL; + } msm_camera_io_w(temp, vfe_dev->vfe_base + reg_cfg_cmd->u.mask_info.reg_offset); break; @@ -443,8 +464,10 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; uint32_t hi_val, lo_val, lo_val1; if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { - if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { + if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset < + reg_cfg_cmd->u.dmi_info.len) || + (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len > cmd_len)) { pr_err("Invalid Hi Table out of bounds\n"); return -EINVAL; } @@ -528,6 +551,12 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, uint32_t *data_ptr = cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4; for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) { + if ((data_ptr < cfg_data) || + (UINT_MAX / sizeof(*data_ptr) < + (data_ptr - cfg_data)) || + (sizeof(*data_ptr) * (data_ptr - cfg_data) > + cmd_len)) + return -EINVAL; *data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base + reg_cfg_cmd->u.rw_info.reg_offset); reg_cfg_cmd->u.rw_info.reg_offset += 4; @@ -545,6 +574,11 @@ int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg) struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd; uint32_t *cfg_data; + if (!proc_cmd->num_cfg) { + pr_err("%s: Passed num_cfg as 0\n", __func__); + return -EINVAL; + } + reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)* proc_cmd->num_cfg, GFP_KERNEL); if (!reg_cfg_cmd) { @@ -856,11 +890,14 @@ void msm_isp_do_tasklet(unsigned long data) } } -void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg) +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg) { struct msm_vfe_axi_src_state *src_state = arg; + if (src_state->input_src >= VFE_SRC_MAX) + return -EINVAL; vfe_dev->axi_data.src_info[src_state->input_src].active = src_state->src_active; + return 0; } int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h index 34b9859..9d9558a 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h @@ -64,7 +64,7 @@ int msm_isp_cal_word_per_line(uint32_t output_format, uint32_t pixel_per_line); int msm_isp_get_bit_per_pixel(uint32_t output_format); irqreturn_t msm_isp_process_irq(int irq_num, void *data); -void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); void msm_isp_do_tasklet(unsigned long data); void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); void msm_isp_process_error_info(struct vfe_device *vfe_dev); -- cgit v1.1