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. Signed-off-by: Saranya Chidura <schidura@codeaurora.org> Change-Id: I9908fa78acbf3152ee791c63fef525f09a9a23d5
This commit is contained in:
parent
0ee94ed17b
commit
f32fe96ca8
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -850,6 +850,14 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&drvdata->usb_lock);
|
mutex_lock(&drvdata->usb_lock);
|
||||||
|
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||||
|
if (drvdata->reading) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||||
|
|
||||||
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
|
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
|
||||||
coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
|
coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
|
||||||
coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
|
coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
|
||||||
|
@ -896,10 +904,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||||
if (drvdata->reading) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
|
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
|
||||||
__tmc_etb_enable(drvdata);
|
__tmc_etb_enable(drvdata);
|
||||||
|
@ -929,11 +933,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
|
||||||
|
|
||||||
dev_info(drvdata->dev, "TMC enabled\n");
|
dev_info(drvdata->dev, "TMC enabled\n");
|
||||||
return 0;
|
return 0;
|
||||||
err1:
|
|
||||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
||||||
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
|
|
||||||
if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
|
|
||||||
usb_qdss_close(drvdata->usbch);
|
|
||||||
err0:
|
err0:
|
||||||
mutex_unlock(&drvdata->usb_lock);
|
mutex_unlock(&drvdata->usb_lock);
|
||||||
clk_disable_unprepare(drvdata->clk);
|
clk_disable_unprepare(drvdata->clk);
|
||||||
|
@ -1328,6 +1327,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
enum tmc_mode mode;
|
enum tmc_mode mode;
|
||||||
|
|
||||||
|
mutex_lock(&drvdata->usb_lock);
|
||||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||||
if (!drvdata->sticky_enable) {
|
if (!drvdata->sticky_enable) {
|
||||||
dev_err(drvdata->dev, "enable tmc once before reading\n");
|
dev_err(drvdata->dev, "enable tmc once before reading\n");
|
||||||
|
@ -1358,11 +1358,13 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
|
||||||
out:
|
out:
|
||||||
drvdata->reading = true;
|
drvdata->reading = true;
|
||||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||||
|
mutex_unlock(&drvdata->usb_lock);
|
||||||
|
|
||||||
dev_info(drvdata->dev, "TMC read start\n");
|
dev_info(drvdata->dev, "TMC read start\n");
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||||
|
mutex_unlock(&drvdata->usb_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1544,8 +1546,12 @@ 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 *drvdata = container_of(file->private_data,
|
||||||
struct tmc_drvdata, miscdev);
|
struct tmc_drvdata, miscdev);
|
||||||
char *bufp = drvdata->buf + *ppos;
|
char *bufp, *end;
|
||||||
char *end = (char *)(drvdata->vaddr + drvdata->size);
|
|
||||||
|
mutex_lock(&drvdata->usb_lock);
|
||||||
|
|
||||||
|
bufp = drvdata->buf + *ppos;
|
||||||
|
end = (char *)(drvdata->vaddr + drvdata->size);
|
||||||
|
|
||||||
if (*ppos + len > drvdata->size)
|
if (*ppos + len > drvdata->size)
|
||||||
len = drvdata->size - *ppos;
|
len = drvdata->size - *ppos;
|
||||||
|
@ -1572,6 +1578,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
|
||||||
|
|
||||||
if (copy_to_user(data, bufp, len)) {
|
if (copy_to_user(data, bufp, len)) {
|
||||||
dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
|
dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
|
||||||
|
mutex_unlock(&drvdata->usb_lock);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1579,6 +1586,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
|
||||||
out:
|
out:
|
||||||
dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
|
dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
|
||||||
__func__, len, (int) (drvdata->size - *ppos));
|
__func__, len, (int) (drvdata->size - *ppos));
|
||||||
|
|
||||||
|
mutex_unlock(&drvdata->usb_lock);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue