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

Commit 88dc4753 authored by Satyajit Desai's avatar Satyajit Desai Committed by Gerrit - the friendly Code Review server
Browse files

coresight-tmc: Re-use ETR buffer across use cases



We can run into use after free scenario for the buffer memory
if enable and read operations happen simultaneously. Add mutex
protection in order to prevent such a scenario.

Change-Id: I3106564a46a9cffc0db8808ba03f78d76c925eca
Signed-off-by: default avatarSatyajit Desai <sadesai@codeaurora.org>
Signed-off-by: default avatarRama Aparna Mallavarapu <aparnam@codeaurora.org>
Signed-off-by: default avatarMulu He <muluhe@codeaurora.org>
parent 0186c4d0
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -1042,15 +1042,17 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
	 * buffer, provided the size matches. Any allocation has to be done
	 * with the lock released.
	 */
	mutex_lock(&drvdata->mem_lock);
	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (!drvdata->etr_buf || (drvdata->etr_buf->size != drvdata->size)) {
		spin_unlock_irqrestore(&drvdata->spinlock, flags);

		/* Allocate memory with the locks released */
		free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata);
		if (IS_ERR(new_buf))
		if (IS_ERR(new_buf)) {
			mutex_unlock(&drvdata->mem_lock);
			return PTR_ERR(new_buf);

		}
		/* Let's try again */
		spin_lock_irqsave(&drvdata->spinlock, flags);
	}
@@ -1087,6 +1089,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
	if (free_buf)
		tmc_etr_free_sysfs_buf(free_buf);

	mutex_unlock(&drvdata->mem_lock);

	if (!ret)
		dev_info(drvdata->dev, "TMC-ETR enabled\n");

@@ -1117,9 +1121,11 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
	unsigned long flags;
	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

	mutex_lock(&drvdata->mem_lock);
	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (drvdata->reading) {
		spin_unlock_irqrestore(&drvdata->spinlock, flags);
		mutex_unlock(&drvdata->mem_lock);
		return;
	}

@@ -1130,7 +1136,7 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
	}

	spin_unlock_irqrestore(&drvdata->spinlock, flags);

	mutex_unlock(&drvdata->mem_lock);
	dev_info(drvdata->dev, "TMC-ETR disabled\n");
}

@@ -1152,6 +1158,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
		return -EINVAL;

	mutex_lock(&drvdata->mem_lock);
	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (drvdata->reading) {
		ret = -EBUSY;
@@ -1177,6 +1184,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
	drvdata->reading = true;
out:
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
	mutex_unlock(&drvdata->mem_lock);

	return ret;
}
@@ -1189,7 +1197,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
	/* config types are set a boot time and never change */
	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
		return -EINVAL;

	mutex_lock(&drvdata->mem_lock);
	spin_lock_irqsave(&drvdata->spinlock, flags);

	/* RE-enable the TMC if need be */
@@ -1216,5 +1224,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
	if (etr_buf)
		tmc_free_etr_buf(etr_buf);


	mutex_unlock(&drvdata->mem_lock);
	return 0;
}
+7 −1
Original line number Diff line number Diff line
@@ -145,18 +145,23 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
	ssize_t actual;
	struct tmc_drvdata *drvdata = container_of(file->private_data,
						   struct tmc_drvdata, miscdev);
	mutex_lock(&drvdata->mem_lock);
	actual = tmc_get_sysfs_trace(drvdata, *ppos, len, &bufp);
	if (actual <= 0)
	if (actual <= 0) {
		mutex_unlock(&drvdata->mem_lock);
		return 0;
	}

	if (copy_to_user(data, bufp, actual)) {
		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
		mutex_unlock(&drvdata->mem_lock);
		return -EFAULT;
	}

	*ppos += actual;
	dev_dbg(drvdata->dev, "%zu bytes copied\n", actual);

	mutex_unlock(&drvdata->mem_lock);
	return actual;
}

@@ -437,6 +442,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
	drvdata->base = base;

	spin_lock_init(&drvdata->spinlock);
	mutex_init(&drvdata->mem_lock);

	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
	drvdata->config_type = BMVAL(devid, 6, 7);
+1 −0
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ struct tmc_drvdata {
	u32			mode;
	enum tmc_config_type	config_type;
	enum tmc_mem_intf_width	memwidth;
	struct mutex		mem_lock;
	u32			trigger_cntr;
	u32			etr_caps;
	struct coresight_csr	*csr;