summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBiswajit Dash <bisdash@google.com>2019-03-13 15:31:19 -0700
committerBiswajit Dash <bisdash@google.com>2019-03-13 15:32:37 -0700
commit67e5e35c6300f177be51936eab3854ee5d49f8f4 (patch)
treeb67f0f9fc00bbeffc2aecda141aab09db08a2759
parent025452fbb24b5b3d3f5523c3592220c507f079d1 (diff)
downloadfts_touch-67e5e35c6300f177be51936eab3854ee5d49f8f4.tar.gz
touchscreen: fts: Fix race conditions in fts diag test interface.
fts touch driver diag core file operations were not thread safe, allowing potentially multiple user space processes/threads to operate on the exposed diag procfs/sysfs entry. This can cause race while allocating/freeing/accessing global command buffer used during diagnostics command execution. This CL fixes multiple such races by allowing only one thread to perform file operation at any given point of time. Bug: 119120571 Bug: 120141034 Change-Id: I9512e39603f1073888edadcbae757b3c2fbaa378 Signed-off-by: Biswajit Dash <bisdash@google.com>
-rw-r--r--fts.c29
-rw-r--r--fts.h5
-rw-r--r--fts_proc.c155
3 files changed, 183 insertions, 6 deletions
diff --git a/fts.c b/fts.c
index 5b1c908..2ef214f 100644
--- a/fts.c
+++ b/fts.c
@@ -1465,6 +1465,17 @@ static ssize_t stm_fts_cmd_store(struct device *dev,
{
int n;
char *p = (char *)buf;
+ struct fts_ts_info *info = dev_get_drvdata(dev);
+
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ return -EBUSY;
+ }
memset(typeOfComand, 0, CMD_STR_LEN * sizeof(u32));
numberParameters = 0;
@@ -1480,6 +1491,9 @@ static ssize_t stm_fts_cmd_store(struct device *dev,
/* numberParameters = n; */
pr_info("Number of Parameters = %d\n", numberParameters);
+
+ mutex_unlock(&info->diag_cmd_lock);
+
return count;
}
@@ -1501,11 +1515,22 @@ static ssize_t stm_fts_cmd_show(struct device *dev,
u8 report = 0;
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ return -EBUSY;
+ }
+
if (fts_set_bus_ref(info, FTS_BUS_REF_SYSFS, true) < 0) {
res = ERROR_BUS_WR;
pr_err("%s: bus is not accessible.\n", __func__);
scnprintf(buf, PAGE_SIZE, "{ %08X }\n", res);
fts_set_bus_ref(info, FTS_BUS_REF_SYSFS, false);
+ mutex_unlock(&info->diag_cmd_lock);
return 0;
}
@@ -2027,6 +2052,8 @@ END:
/* pr_err("numberParameters = %d\n", numberParameters); */
fts_set_bus_ref(info, FTS_BUS_REF_SYSFS, false);
+ mutex_unlock(&info->diag_cmd_lock);
+
return index;
}
@@ -4692,6 +4719,8 @@ static int fts_probe(struct spi_device *client)
input_set_capability(info->input_dev, EV_KEY, KEY_MENU);
#endif
+ mutex_init(&info->diag_cmd_lock);
+
mutex_init(&(info->input_report_mutex));
mutex_init(&info->bus_mutex);
diff --git a/fts.h b/fts.h
index b35c42e..1ed21fa 100644
--- a/fts.h
+++ b/fts.h
@@ -415,6 +415,11 @@ struct fts_ts_info {
struct tbn_context *tbn;
#endif
+ /* Allow only one thread to execute diag command code*/
+ struct mutex diag_cmd_lock;
+ /* Allow one process to open procfs node */
+ bool diag_node_open;
+
/* Preallocated i/o read buffer */
u8 io_read_buf[READ_CHUNK + DUMMY_FIFO];
/* Preallocated i/o write buffer */
diff --git a/fts_proc.c b/fts_proc.c
index 060ba5a..ff0e4b0 100644
--- a/fts_proc.c
+++ b/fts_proc.c
@@ -679,11 +679,139 @@ static const struct seq_operations fts_seq_ops = {
* @param file file associated to the file node
* @return error code, 0 if success
*/
-static int fts_open(struct inode *inode, struct file *file)
+static int fts_driver_test_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &fts_seq_ops);
+ struct fts_ts_info *info = dev_get_drvdata(getDev());
+ int retval;
+
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ /* Allowing only a single process to open diag procfs node */
+ if (info->diag_node_open == true) {
+ pr_err("%s: Blocking multiple open\n", __func__);
+ retval = -EBUSY;
+ goto unlock;
+ }
+
+ retval = seq_open(file, &fts_seq_ops);
+ if(!retval) {
+ info->diag_node_open = true;
+ }
+
+unlock:
+ mutex_unlock(&info->diag_cmd_lock);
+exit:
+ return retval;
};
+/**
+ * This function closes a sequential file
+ * @param inode Inode in the file system that was called and triggered this
+ * function
+ * @param file file associated to the file node
+ * @return error code, 0 if success
+ */
+static int fts_driver_test_release(struct inode *inode, struct file *file)
+{
+ struct fts_ts_info *info = dev_get_drvdata(getDev());
+ int retval;
+
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ retval = seq_release(inode, file);
+ info->diag_node_open = false;
+
+ mutex_unlock(&info->diag_cmd_lock);
+exit:
+ return retval;
+}
+
+
+/**
+ * This function reads a sequential file
+ * @param file file associated to the file node
+ * @param buf userspace buffer where the newly read data should be placed
+ * @param count size of the requested transfer.
+ * @param pos start position from which data should be written in the file.
+ * @return error code, 0 if success
+ */
+static ssize_t fts_driver_test_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct fts_ts_info *info = dev_get_drvdata(getDev());
+ ssize_t bytes_read = -EINVAL;
+
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ bytes_read = -ENODEV;
+ goto exit;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ bytes_read = -EBUSY;
+ goto exit;
+ }
+
+ bytes_read = seq_read(file, buf, count, pos);
+
+ mutex_unlock(&info->diag_cmd_lock);
+exit:
+ return bytes_read;
+}
+
+/**
+ * This function moves the cursor position within a file.
+ * @param file file associated to the file node
+ * @param offset offset relative to the current file position.
+ * @param whence defines where to seek from.
+ * @return error code, 0 if success
+ */
+static loff_t fts_driver_test_lseek(struct file *file, loff_t offset,
+ int whence)
+{
+ struct fts_ts_info *info = dev_get_drvdata(getDev());
+ loff_t retval;
+
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ retval = seq_lseek(file, offset, whence);
+
+ mutex_unlock(&info->diag_cmd_lock);
+
+exit:
+ return retval;
+}
/*****************************************************************************/
@@ -743,6 +871,18 @@ static ssize_t fts_driver_test_write(struct file *file, const char __user *buf,
LimitFile lim;
const char *limits_file = info->board->limits_name;
+ if (!info) {
+ pr_err("%s: Unable to access driver data\n", __func__);
+ count = -ENODEV;
+ goto exit;
+ }
+
+ if (!mutex_trylock(&info->diag_cmd_lock)) {
+ pr_err("%s: Blocking concurrent access\n", __func__);
+ count = -EBUSY;
+ goto exit;
+ }
+
mess.dummy = 0;
mess.action = 0;
mess.msg_size = 0;
@@ -3466,6 +3606,9 @@ ERROR:
fts_set_bus_ref(info, FTS_BUS_REF_SYSFS, false);
+ mutex_unlock(&info->diag_cmd_lock);
+
+exit:
return count;
}
@@ -3476,11 +3619,11 @@ ERROR:
* operation on a device file node (open. read, write etc.)
*/
static struct file_operations fts_driver_test_ops = {
- .open = fts_open,
- .read = seq_read,
+ .open = fts_driver_test_open,
+ .read = fts_driver_test_read,
.write = fts_driver_test_write,
- .llseek = seq_lseek,
- .release = seq_release
+ .llseek = fts_driver_test_lseek,
+ .release = fts_driver_test_release
};
/*****************************************************************************/