summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorAndrew Chant <achant@google.com>2016-09-15 16:19:50 -0700
committerHimanshu Aggarwal <haggarwa@codeaurora.org>2016-12-01 10:28:16 +0530
commitae39f47e9b8f736b56617cdfe3ed8697c61f7554 (patch)
treebd097c5c99cd2fc9d6dcb1261143313d7db18362 /drivers/input
parent0380dc86d2a75a4ae7d4246a94a5d767b0b75de4 (diff)
Input: synaptics: check input, prevent sysfs races
concurrent sysfs calls on the fw updater can cause ugly race conditions. Return EBUSY on concurrent sysfs calls. For sysfs calls which generate deferred work, prevent the deferred work from running concurrently with other sysfs calls. Also check that ext_data_source is appropriately sized and allocated, based on a patch by Gengjia Chen (chengjia4574@gmail.com). Signed-off-by: Andrew Chant <achant@google.com> Change-Id:I5bbe4992f3fd2d23db288296eaeb61f5831098e9 Bug: 30799828 Bug: 31252388 Git-repo: https://android.googlesource.com/kernel/msm.git Git-commit: 287ce2ccfefe68067c1f9f5175b6664bf7397fe6 Signed-off-by: Srinivasa Rao Kuppala <srkupp@codeaurora.org>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c91
1 files changed, 80 insertions, 11 deletions
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index f001706236ab..0ec16e606545 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -358,6 +358,7 @@ static struct device_attribute attrs[] = {
static struct synaptics_rmi4_fwu_handle *fwu;
DECLARE_COMPLETION(fwu_dsx_remove_complete);
+DEFINE_MUTEX(dsx_fwu_sysfs_mutex);
static unsigned int extract_uint_le(const unsigned char *ptr)
{
@@ -1589,28 +1590,49 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file,
char *buf, loff_t pos, size_t count)
{
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
if (count < fwu->config_size) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Not enough space (%zu bytes) in buffer\n",
__func__, count);
- return -EINVAL;
+ retval = -EINVAL;
+ goto show_image_exit;
}
memcpy(buf, fwu->read_config_buf, fwu->config_size);
-
- return fwu->config_size;
+ retval = fwu->config_size;
+show_image_exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_store_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (count > (fwu->image_size - fwu->data_pos)) {
dev_err(fwu->rmi4_data->pdev->dev.parent,
"%s: Not enough space in buffer\n",
__func__);
- return -EINVAL;
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (!fwu->ext_data_source) {
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "%s: Need to set imagesize\n",
+ __func__);
+ retval = -EINVAL;
+ goto exit;
}
memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
@@ -1619,16 +1641,21 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file,
fwu->data_pos += count;
+exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return count;
}
static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- int retval;
+ ssize_t retval;
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1657,6 +1684,9 @@ exit:
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1667,6 +1697,9 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1700,6 +1733,9 @@ exit:
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1710,6 +1746,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev,
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1733,6 +1772,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev,
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1749,7 +1791,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev,
if (input != 1)
return -EINVAL;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
retval = fwu_do_read_config();
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to read config\n",
@@ -1770,7 +1816,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
if (retval)
return retval;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
fwu->config_area = config_area;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return count;
}
@@ -1778,17 +1827,30 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
static ssize_t fwu_sysfs_image_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0)
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ retval = snprintf(buf, PAGE_SIZE, "%s\n",
fwu->rmi4_data->fw_name);
else
- return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_image_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- if (sscanf(buf, "%s", fwu->image_name) != 1)
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+ retval = sscanf(buf, "%49s", fwu->image_name);
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+
+ if (retval != 1)
return -EINVAL;
return count;
@@ -1801,9 +1863,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev,
unsigned long size;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
retval = sstrtoul(buf, 10, &size);
if (retval)
- return retval;
+ goto exit;
fwu->image_size = size;
fwu->data_pos = 0;
@@ -1814,10 +1879,14 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev,
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for image data\n",
__func__);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto exit;
}
- return count;
+ retval = count;
+exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_block_size_show(struct device *dev,