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

Commit 8f8d50ed authored by Rishabh Jain's avatar Rishabh Jain
Browse files

msm: camera: cdm: Secure freeing of request lists using locks



If release is called while processing of request, there is
a possibility of freeing the lists simultaneously in two
contexts due to interrupt and release ioctl call. This can
result into double free.
Securing the release of request lists in interrupt handler
and deinit using locks.

CRs-Fixed: 2641842
Change-Id: I248fa80a32836c3a89494072c55af852c3d518eb
Signed-off-by: default avatarRishabh Jain <risjai@codeaurora.org>
parent ad4a8914
Loading
Loading
Loading
Loading
+23 −3
Original line number Diff line number Diff line
@@ -1141,7 +1141,12 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data)
	int i;

	CAM_DBG(CAM_CDM, "Got irq");

	spin_lock(&cdm_hw->hw_lock);
	if (cdm_hw->hw_state == CAM_HW_STATE_POWER_DOWN) {
		CAM_DBG(CAM_CDM, "CDM is in power down state");
		spin_unlock(&cdm_hw->hw_lock);
		return IRQ_HANDLED;
	}
	for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) {
		if (cam_cdm_read_hw_reg(cdm_hw,
				cdm_core->offsets->irq_reg[i]->irq_status,
@@ -1162,6 +1167,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data)
			cdm_core->offsets->cmn_reg->usr_data,
			&user_data))
		CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ data");
	spin_unlock(&cdm_hw->hw_lock);

	for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) {
		if (!irq_status[i])
@@ -1565,6 +1571,7 @@ int cam_hw_cdm_init(void *hw_priv,
	struct cam_hw_soc_info *soc_info = NULL;
	struct cam_cdm *cdm_core = NULL;
	int rc, i, reset_hw_hdl = 0x0;
	unsigned long flags;

	if (!hw_priv)
		return -EINVAL;
@@ -1578,6 +1585,9 @@ int cam_hw_cdm_init(void *hw_priv,
		CAM_ERR(CAM_CDM, "Enable platform failed");
		goto end;
	}
	spin_lock_irqsave(&cdm_hw->hw_lock, flags);
	cdm_hw->hw_state = CAM_HW_STATE_POWER_UP;
	spin_unlock_irqrestore(&cdm_hw->hw_lock, flags);

	CAM_DBG(CAM_CDM, "Enable soc done");

@@ -1598,7 +1608,6 @@ int cam_hw_cdm_init(void *hw_priv,
		goto disable_return;
	} else {
		CAM_DBG(CAM_CDM, "CDM Init success");
		cdm_hw->hw_state = CAM_HW_STATE_POWER_UP;
		for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++)
			cam_cdm_write_hw_reg(cdm_hw,
					cdm_core->offsets->irq_reg[i]->irq_mask,
@@ -1609,6 +1618,9 @@ int cam_hw_cdm_init(void *hw_priv,

disable_return:
	rc = -EIO;
	spin_lock_irqsave(&cdm_hw->hw_lock, flags);
	cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
	spin_unlock_irqrestore(&cdm_hw->hw_lock, flags);
	cam_soc_util_disable_platform_resource(soc_info, true, true);
end:
	return rc;
@@ -1624,6 +1636,7 @@ int cam_hw_cdm_deinit(void *hw_priv,
	int rc = 0, i;
	uint32_t reset_val = 1;
	long time_left;
	unsigned long                             flags;

	if (!hw_priv)
		return -EINVAL;
@@ -1631,6 +1644,9 @@ int cam_hw_cdm_deinit(void *hw_priv,
	soc_info = &cdm_hw->soc_info;
	cdm_core = (struct cam_cdm *)cdm_hw->core_info;

	for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++)
		mutex_lock(&cdm_core->bl_fifo[i].fifo_lock);

	/*clear bl request */
	for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) {
		list_for_each_entry_safe(node, tnode,
@@ -1674,13 +1690,17 @@ int cam_hw_cdm_deinit(void *hw_priv,
	}

	clear_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status);
	for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++)
		mutex_unlock(&cdm_core->bl_fifo[i].fifo_lock);

	spin_lock_irqsave(&cdm_hw->hw_lock, flags);
	cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
	spin_unlock_irqrestore(&cdm_hw->hw_lock, flags);
	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
	if (rc) {
		CAM_ERR(CAM_CDM, "disable platform failed");
	} else {
		CAM_DBG(CAM_CDM, "CDM Deinit success");
		cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
	}

	return rc;