summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSatyajit Desai <sadesai@codeaurora.org>2017-06-13 15:55:20 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-06-28 21:18:31 -0700
commit57ffcb3ed871815a0c4af6a654a1d787204fa535 (patch)
tree3989df42ee15db81b93cd2d3d49bbceb18b641da
parent823d04d683bfa9b6da415db882028b05fc13f1b8 (diff)
coresight: tmc: Fix use after free issue with tmc read
Fix race condition seen between reading tmc buffer and enabling the device. The race condition can result in a use after free issue if the buffer is released while a read is in progress. Change-Id: I44e0f8b95ddfae5acac6fcc59e78a7741aaa97cc Signed-off-by: Saranya Chidura <schidura@codeaurora.org>
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 316d8b783d94..691c7bb3afac 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -764,6 +764,16 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
pm_runtime_get_sync(drvdata->dev);
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);
+ pm_runtime_put(drvdata->dev);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR &&
drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
/*
@@ -807,19 +817,8 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
}
- mutex_unlock(&drvdata->mem_lock);
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR
- && drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
- usb_qdss_close(drvdata->usbch);
- pm_runtime_put(drvdata->dev);
-
- return -EBUSY;
- }
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
tmc_etb_enable_hw(drvdata);
@@ -845,6 +844,7 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
*/
drvdata->sticky_enable = true;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ mutex_unlock(&drvdata->mem_lock);
dev_info(drvdata->dev, "TMC enabled\n");
return 0;
@@ -1140,6 +1140,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
unsigned long flags;
enum tmc_mode mode;
+ mutex_lock(&drvdata->mem_lock);
spin_lock_irqsave(&drvdata->spinlock, flags);
if (!drvdata->sticky_enable) {
dev_err(drvdata->dev, "enable tmc once before reading\n");
@@ -1172,11 +1173,13 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
out:
drvdata->reading = true;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ mutex_unlock(&drvdata->mem_lock);
dev_info(drvdata->dev, "TMC read start\n");
return 0;
err:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ mutex_unlock(&drvdata->mem_lock);
return ret;
}
@@ -1353,7 +1356,11 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
{
struct tmc_drvdata *drvdata = container_of(file->private_data,
struct tmc_drvdata, miscdev);
- char *bufp = drvdata->buf + *ppos;
+ char *bufp;
+
+ mutex_lock(&drvdata->mem_lock);
+
+ bufp = drvdata->buf + *ppos;
if (*ppos + len > drvdata->size)
len = drvdata->size - *ppos;
@@ -1375,6 +1382,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
if (copy_to_user(data, bufp, len)) {
dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+ mutex_unlock(&drvdata->mem_lock);
return -EFAULT;
}
@@ -1382,6 +1390,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
__func__, len, (int)(drvdata->size - *ppos));
+
+ mutex_unlock(&drvdata->mem_lock);
return len;
}