From 8ad163e831a2b2c30551edb360f168a604cdb0bb Mon Sep 17 00:00:00 2001 From: Alok Kediya Date: Fri, 12 Dec 2014 04:20:59 -0800 Subject: msm: camera: isp: Validate input parameter for vfe_write and vfe_read Validate input parameters for read and write operations in vfe to ensure operations are performed within vfe register boundary and within structure limits passed by caller. Change-Id: If3719de65b32773c2b6ff904da76a951dbfb11eb Signed-off-by: Alok Kediya --- .../platform/msm/camera_v2/isp/msm_isp_util.c | 162 ++++++++++++++------- .../msm/camera_v2/sensor/io/msm_camera_io_util.c | 11 ++ .../msm/camera_v2/sensor/io/msm_camera_io_util.h | 2 + 3 files changed, 119 insertions(+), 56 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 620c01a..e1b79ce 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 @@ -494,9 +494,24 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd, uint32_t *cfg_data, uint32_t cmd_len) { + if (!vfe_dev || !reg_cfg_cmd) { + pr_err("%s:%d failed: vfe_dev %p reg_cfg_cmd %p\n", __func__, + __LINE__, vfe_dev, reg_cfg_cmd); + return -EINVAL; + } + if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) && + (!cfg_data || !cmd_len)) { + pr_err("%s:%d failed: cmd type %d cfg_data %p cmd_len %d\n", + __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data, + cmd_len); + return -EINVAL; + } + + /* Validate input parameters */ switch (reg_cfg_cmd->cmd_type) { case VFE_WRITE: - case VFE_READ: { + case VFE_READ: + case VFE_WRITE_MB: { if ((reg_cfg_cmd->u.rw_info.reg_offset > (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || ((reg_cfg_cmd->u.rw_info.reg_offset + @@ -522,6 +537,58 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, } break; } + + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + 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.lo_tbl_offset) || + (reg_cfg_cmd->u.dmi_info.hi_tbl_offset - + reg_cfg_cmd->u.dmi_info.lo_tbl_offset != + (sizeof(uint32_t)))) { + pr_err("%s:%d hi %d lo %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset); + return -EINVAL; + } + if (reg_cfg_cmd->u.dmi_info.len <= sizeof(uint32_t)) { + pr_err("%s:%d len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.len); + return -EINVAL; + } + if (((UINT_MAX - + reg_cfg_cmd->u.dmi_info.hi_tbl_offset) < + (reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t))) || + ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t)) > cmd_len)) { + pr_err("%s:%d hi_tbl_offset %d len %d cmd %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); + return -EINVAL; + } + } + if ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset > + (UINT_MAX - reg_cfg_cmd->u.dmi_info.len)) || + ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset + + reg_cfg_cmd->u.dmi_info.len) > cmd_len)) { + pr_err("%s:%d lo_tbl_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.lo_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); + return -EINVAL; + } + break; + } + default: break; } @@ -535,39 +602,27 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, break; } 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); + msm_camera_io_memcpy_mb(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); 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) || + 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; } + 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; msm_camera_io_w(temp, vfe_dev->vfe_base + reg_cfg_cmd->u.mask_info.reg_offset); break; @@ -579,22 +634,9 @@ 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 ((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; - } hi_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; } - - if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Lo Table out of bounds\n"); - return -EINVAL; - } lo_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) @@ -627,30 +669,18 @@ 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_READ_DMI_64BIT) { - if (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; - } hi_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; } - if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Lo Table out of bounds\n"); - return -EINVAL; - } lo_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; - for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { - hi_val = msm_camera_io_r(vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset); - *hi_tbl_ptr++ = hi_val; - } + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { lo_val = msm_camera_io_r(vfe_dev->vfe_base + vfe_dev->hw_info->dmi_reg_offset + 0x4); @@ -660,6 +690,13 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, lo_val |= lo_val1 << 16; } *lo_tbl_ptr++ = lo_val; + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + *hi_tbl_ptr = hi_val; + hi_tbl_ptr += 2; + lo_tbl_ptr++; + } } break; } @@ -698,7 +735,7 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, if ((data_ptr < cfg_data) || (UINT_MAX / sizeof(*data_ptr) < (data_ptr - cfg_data)) || - (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 + @@ -707,9 +744,16 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, } break; } - case GET_SOC_HW_VER: - *cfg_data = vfe_dev->soc_hw_version; - break; + case GET_SOC_HW_VER: { + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + *cfg_data = vfe_dev->soc_hw_version; + break; + } case GET_MAX_CLK_RATE: { int rc = 0; @@ -728,6 +772,12 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, break; } case SET_WM_UB_SIZE: { + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } vfe_dev->vfe_ub_size = *cfg_data; break; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c index 46a0542..7d369ff 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c @@ -107,6 +107,17 @@ void msm_camera_io_memcpy(void __iomem *dest_addr, msm_camera_io_dump(dest_addr, len); } +void msm_camera_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + + for (i = 0; i < (len / 4); i++) + msm_camera_io_w_mb(*s++, d++); +} + int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, struct msm_cam_clk_info *clk_src_info, int num_clk) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h index 2e6f809..90925a9 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h @@ -28,6 +28,8 @@ u32 msm_camera_io_r_mb(void __iomem *addr); void msm_camera_io_dump(void __iomem *addr, int size); void msm_camera_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len); +void msm_camera_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, u32 len); int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, struct msm_cam_clk_info *clk_src_info, int num_clk); int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, -- cgit v1.1