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: Satyajit Desai <sadesai@codeaurora.org>
Signed-off-by: Rama Aparna Mallavarapu <aparnam@codeaurora.org>
Signed-off-by: Mulu He <muluhe@codeaurora.org>
Signed-off-by: Tingwei Zhang <tingwei@codeaurora.org>
This commit is contained in:
Satyajit Desai 2017-06-01 18:41:33 -07:00 • committed by Gerrit - the friendly Code Review server
commit a8928b2c6d
3 changed files with 21 additions and 4 deletions

View file

@ -1135,6 +1135,7 @@ 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);
sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
@ -1142,9 +1143,10 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
/* 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);
}
@ -1191,6 +1193,7 @@ out:
tmc_etr_free_sysfs_buf(free_buf);
tmc_etr_byte_cntr_start(drvdata->byte_cntr);
mutex_unlock(&drvdata->mem_lock);
if (!ret)
dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
@ -1636,10 +1639,12 @@ static int 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 -EBUSY;
}
@ -1667,6 +1672,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
tmc_etr_free_sysfs_buf(drvdata->etr_buf);
drvdata->etr_buf = NULL;
}
mutex_unlock(&drvdata->mem_lock);
dev_info(&csdev->dev, "TMC-ETR disabled\n");
return 0;
}
@ -1692,6 +1698,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;
@ -1720,6 +1727,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;
}
@ -1732,7 +1740,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 */
@ -1759,5 +1767,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
if (sysfs_buf)
tmc_etr_free_sysfs_buf(sysfs_buf);
mutex_unlock(&drvdata->mem_lock);
return 0;
}

View file

@ -184,19 +184,24 @@ 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->csdev->dev,
"%s: copy_to_user failed\n", __func__);
mutex_unlock(&drvdata->mem_lock);
return -EFAULT;
}
*ppos += actual;
dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual);
mutex_unlock(&drvdata->mem_lock);
return actual;
}
@ -512,6 +517,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);

View file

@ -204,6 +204,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 idr idr;