DivestOS/Patches/Linux_CVEs/CVE-2016-6745/ANY/0005.patch
2017-11-07 17:32:46 -05:00

402 lines
10 KiB
Diff

From f5c96a8c96615490b72357b1c0940196f7dde474 Mon Sep 17 00:00:00 2001
From: Andrew Chant <achant@google.com>
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 <achant@google.com>
---
.../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 <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/firmware.h>
@@ -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;
}