From a8928b2c6dc64a41941a4d776d30db8f4fff7cfd Mon Sep 17 00:00:00 2001 From: Satyajit Desai Date: Thu, 1 Jun 2017 18:41:33 -0700 Subject: [PATCH] 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 Signed-off-by: Rama Aparna Mallavarapu Signed-off-by: Mulu He Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 16 +++++++++++++--- drivers/hwtracing/coresight/coresight-tmc.c | 8 +++++++- drivers/hwtracing/coresight/coresight-tmc.h | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 895a0eced083..a1f2e64171ed 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -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; } diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index bd6cf3801b24..d7b5fcf88d60 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -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); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index bd99cb6c016d..25298c5b6e3d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -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;