diff options
author | Biswajit Dash <bisdash@google.com> | 2019-03-13 15:31:19 -0700 |
---|---|---|
committer | Biswajit Dash <bisdash@google.com> | 2019-03-13 15:32:37 -0700 |
commit | 67e5e35c6300f177be51936eab3854ee5d49f8f4 (patch) | |
tree | b67f0f9fc00bbeffc2aecda141aab09db08a2759 | |
parent | 025452fbb24b5b3d3f5523c3592220c507f079d1 (diff) | |
download | fts_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.c | 29 | ||||
-rw-r--r-- | fts.h | 5 | ||||
-rw-r--r-- | fts_proc.c | 155 |
3 files changed, 183 insertions, 6 deletions
@@ -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); @@ -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 */ @@ -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 }; /*****************************************************************************/ |