From f5c96a8c96615490b72357b1c0940196f7dde474 Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Wed, 14 Sep 2016 14:12:13 -0700 Subject: [PATCH] input: touchscreen: Synaptics: prevent sysfs races Concurrent sysfs calls can cause ugly race conditions. Return EBUSY on concurrent sysfs calls, and prevent sysfs calls during initial fw load. Change-Id: Iec3db7f3fe9d33104319fd3e2bbf1d70ba68221b Bug: 31252388 Signed-off-by: Andrew Chant --- .../synaptics_dsx_fw_update.c | 133 +++++++++++++++------ 1 file changed, 99 insertions(+), 34 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_fw_update.c index 3887f79a97a08..af6f92553aa7e 100644 --- a/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_fw_update.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -768,6 +769,8 @@ static struct device_attribute attrs[] = { static struct synaptics_rmi4_fwu_handle *fwu; DECLARE_COMPLETION(fwu_remove_complete); +DEFINE_MUTEX(fwu_sysfs_mutex); + #ifdef HTC_FEATURE static uint32_t syn_crc(uint16_t *data, uint32_t len) { @@ -5087,6 +5090,9 @@ static void fwu_startup_fw_update_work(struct work_struct *work) } #endif + /* Prevent sysfs operations during initial update. */ + mutex_lock(&fwu_sysfs_mutex); + #ifdef HTC_FEATURE wake_lock(&fwu->fwu_wake_lock); if (bdata->update_feature & SYNAPTICS_RMI4_UPDATE_IMAGE) @@ -5101,7 +5107,7 @@ static void fwu_startup_fw_update_work(struct work_struct *work) #else synaptics_fw_updater(NULL); #endif - + mutex_unlock(&fwu_sysfs_mutex); return; } #endif @@ -5113,11 +5119,15 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file, int retval; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (count < fwu->config_size) { dev_err(rmi4_data->pdev->dev.parent, "%s: Not enough space (%d bytes) in buffer\n", __func__, (unsigned int)count); - return -EINVAL; + retval = -EINVAL; + goto show_image_exit; } retval = secure_memcpy(buf, count, fwu->read_config_buf, @@ -5126,10 +5136,14 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file, dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to copy config data\n", __func__); - return retval; + goto show_image_exit; } - return fwu->config_size; + retval = fwu->config_size; + +show_image_exit: + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_store_image(struct file *data_file, @@ -5139,18 +5153,24 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file, int retval; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + retval = secure_memcpy(&fwu->ext_data_source[fwu->data_pos], fwu->image_size - fwu->data_pos, buf, count, count); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to copy image data\n", __func__); - return retval; + goto store_image_exit; } fwu->data_pos += count; + retval = count; - return count; +store_image_exit: + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, @@ -5160,9 +5180,12 @@ static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto do_recovery_store_exit; } if (!fwu->in_ub_mode) { @@ -5170,11 +5193,13 @@ static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, "%s: Not in microbootloader mode\n", __func__); retval = -EINVAL; - goto exit; + goto do_recovery_store_exit; } - if (!fwu->ext_data_source) - return -EINVAL; + if (!fwu->ext_data_source) { + retval = -EINVAL; + goto do_recovery_store_exit; + } else fwu->image = fwu->ext_data_source; @@ -5183,15 +5208,18 @@ static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to do recovery\n", __func__); - goto exit; + goto free_data_source_recovery_exit; } retval = count; -exit: +free_data_source_recovery_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; fwu->image = NULL; + +do_recovery_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -5201,9 +5229,13 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, int retval; unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto reflash_store_exit; } if (fwu->in_ub_mode) { @@ -5211,7 +5243,7 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, "%s: In microbootloader mode\n", __func__); retval = -EINVAL; - goto exit; + goto reflash_store_exit; } //if (!fwu->ext_data_source) @@ -5226,7 +5258,7 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, if ((input != NORMAL) && (input != FORCE)) { retval = -EINVAL; - goto exit; + goto reflash_store_exit; } if (input == FORCE) @@ -5237,12 +5269,12 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to do reflash\n", __func__); - goto exit; + goto reflash_store_free_exit; } retval = count; -exit: +reflash_store_free_exit: if (fwu->ext_data_source != NULL) { kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; @@ -5250,6 +5282,9 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, fwu->image = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = DO_LOCKDOWN; + +reflash_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -5260,14 +5295,17 @@ 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(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto write_config_store_exit; } if (input != 1) { retval = -EINVAL; - goto exit; + goto write_config_store_exit; } if (fwu->in_ub_mode) { @@ -5275,28 +5313,32 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, "%s: In microbootloader mode\n", __func__); retval = -EINVAL; - goto exit; + goto write_config_store_exit; } - if (!fwu->ext_data_source) - return -EINVAL; - else + if (!fwu->ext_data_source) { + retval = -EINVAL; + goto write_config_store_exit; + } else { fwu->image = fwu->ext_data_source; - + } retval = fwu_start_write_config(); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to write config\n", __func__); - goto exit; + goto write_config_store_free_exit; } retval = count; -exit: +write_config_store_free_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; fwu->image = NULL; + +write_config_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -5320,7 +5362,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev, return -EINVAL; } + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; retval = fwu_do_read_config(); + mutex_unlock(&fwu_sysfs_mutex); + if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to read config\n", @@ -5341,7 +5387,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev, if (retval) return retval; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; fwu->config_area = config_area; + mutex_unlock(&fwu_sysfs_mutex); return count; } @@ -5352,8 +5401,12 @@ static ssize_t fwu_sysfs_image_name_store(struct device *dev, int retval; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, buf, count, count); + mutex_unlock(&fwu_sysfs_mutex); + if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to copy image file name\n", @@ -5375,6 +5428,9 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, if (retval) return retval; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + fwu->image_size = size; fwu->data_pos = 0; @@ -5382,6 +5438,8 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, kfree(fwu->ext_data_source); } fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL); + mutex_unlock(&fwu_sysfs_mutex); + if (!fwu->ext_data_source) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to alloc mem for image data\n", @@ -5441,14 +5499,17 @@ static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto write_guest_code_store_exit; } if (input != 1) { retval = -EINVAL; - goto exit; + goto write_guest_code_store_exit; } if (fwu->in_ub_mode) { @@ -5456,28 +5517,32 @@ static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev, "%s: In microbootloader mode\n", __func__); retval = -EINVAL; - goto exit; + goto write_guest_code_store_exit; } - if (!fwu->ext_data_source) - return -EINVAL; - else + if (!fwu->ext_data_source) { + retval = -EINVAL; + goto write_guest_code_store_exit; + } else { fwu->image = fwu->ext_data_source; + } retval = fwu_start_write_guest_code(); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to write guest code\n", __func__); - goto exit; + goto write_guest_code_store_free_exit; } retval = count; -exit: +write_guest_code_store_free_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; fwu->image = NULL; +write_guest_code_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; }