mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-25 15:39:26 -05:00
387 lines
9.6 KiB
Diff
387 lines
9.6 KiB
Diff
|
From 19055017169363f176693c3e41ebdfc3c8e11ef4 Mon Sep 17 00:00:00 2001
|
||
|
From: Andrew Chant <achant@google.com>
|
||
|
Date: Thu, 15 Sep 2016 12:10:56 -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: I5e295c4cd7c3ba4b998de5b75f9b631679e7c39f
|
||
|
Signed-off-by: Andrew Chant <achant@google.com>
|
||
|
Bug: 31252388
|
||
|
---
|
||
|
.../synaptics_dsx25/synaptics_dsx_fw_update.c | 138 +++++++++++++++------
|
||
|
1 file changed, 99 insertions(+), 39 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/input/touchscreen/synaptics_dsx25/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx25/synaptics_dsx_fw_update.c
|
||
|
index 3edeaa22aa336..908693bd26a43 100755
|
||
|
--- a/drivers/input/touchscreen/synaptics_dsx25/synaptics_dsx_fw_update.c
|
||
|
+++ b/drivers/input/touchscreen/synaptics_dsx25/synaptics_dsx_fw_update.c
|
||
|
@@ -20,6 +20,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>
|
||
|
@@ -654,6 +655,7 @@ static struct device_attribute attrs[] = {
|
||
|
static struct synaptics_rmi4_fwu_handle *fwu;
|
||
|
|
||
|
DECLARE_COMPLETION(dsx_fwu_remove_complete);
|
||
|
+DEFINE_MUTEX(fwu_sysfs_mutex);
|
||
|
|
||
|
static bool tp_2k_panel = false;
|
||
|
/**
|
||
|
@@ -3719,14 +3721,18 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file,
|
||
|
struct kobject *kobj, struct bin_attribute *attributes,
|
||
|
char *buf, loff_t pos, size_t count)
|
||
|
{
|
||
|
- int retval;
|
||
|
+ ssize_t 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 (%zu bytes) in buffer\n",
|
||
|
__func__, count);
|
||
|
- return -EINVAL;
|
||
|
+ retval = -EINVAL;
|
||
|
+ goto show_image_exit;
|
||
|
}
|
||
|
|
||
|
retval = secure_memcpy(buf, count, fwu->read_config_buf,
|
||
|
@@ -3735,43 +3741,56 @@ 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,
|
||
|
struct kobject *kobj, struct bin_attribute *attributes,
|
||
|
char *buf, loff_t pos, size_t count)
|
||
|
{
|
||
|
- int retval;
|
||
|
+ ssize_t 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;
|
||
|
|
||
|
+store_image_exit:
|
||
|
+ mutex_unlock(&fwu_sysfs_mutex);
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t fwu_sysfs_do_recovery_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(&fwu_sysfs_mutex))
|
||
|
+ return -EBUSY;
|
||
|
+
|
||
|
if (sscanf(buf, "%u", &input) != 1) {
|
||
|
retval = -EINVAL;
|
||
|
- goto exit;
|
||
|
+ goto recovery_store_exit;
|
||
|
}
|
||
|
|
||
|
if (!fwu->in_ub_mode) {
|
||
|
@@ -3779,28 +3798,32 @@ static ssize_t fwu_sysfs_do_recovery_store(struct device *dev,
|
||
|
"%s: Not in microbootloader mode\n",
|
||
|
__func__);
|
||
|
retval = -EINVAL;
|
||
|
- goto exit;
|
||
|
+ goto recovery_store_exit;
|
||
|
}
|
||
|
|
||
|
- if (!fwu->ext_data_source)
|
||
|
- return -EINVAL;
|
||
|
- else
|
||
|
+ if (!fwu->ext_data_source) {
|
||
|
+ retval = -EINVAL;
|
||
|
+ goto recovery_store_exit;
|
||
|
+ } else {
|
||
|
fwu->image = fwu->ext_data_source;
|
||
|
+ }
|
||
|
|
||
|
retval = fwu_start_recovery();
|
||
|
if (retval < 0) {
|
||
|
dev_err(rmi4_data->pdev->dev.parent,
|
||
|
"%s: Failed to do recovery\n",
|
||
|
__func__);
|
||
|
- goto exit;
|
||
|
+ goto recovery_store_free_exit;
|
||
|
}
|
||
|
|
||
|
retval = count;
|
||
|
|
||
|
-exit:
|
||
|
+recovery_store_free_exit:
|
||
|
kfree(fwu->ext_data_source);
|
||
|
fwu->ext_data_source = NULL;
|
||
|
fwu->image = NULL;
|
||
|
+recovery_store_exit:
|
||
|
+ mutex_unlock(&fwu_sysfs_mutex);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
@@ -3811,15 +3834,20 @@ 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(&fwu_sysfs_mutex))
|
||
|
+ return -EBUSY;
|
||
|
+
|
||
|
if (sscanf(buf, "%u", &input) != 1) {
|
||
|
retval = -EINVAL;
|
||
|
- goto exit;
|
||
|
+ goto reflash_store_exit;
|
||
|
}
|
||
|
|
||
|
- if (!fwu->ext_data_source)
|
||
|
- return -EINVAL;
|
||
|
- else
|
||
|
+ if (!fwu->ext_data_source) {
|
||
|
+ retval = -EINVAL;
|
||
|
+ goto reflash_store_exit;
|
||
|
+ } else {
|
||
|
fwu->image = fwu->ext_data_source;
|
||
|
+ }
|
||
|
|
||
|
if (input & LOCKDOWN) {
|
||
|
fwu->do_lockdown = true;
|
||
|
@@ -3828,7 +3856,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)
|
||
|
@@ -3839,17 +3867,19 @@ 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:
|
||
|
kfree(fwu->ext_data_source);
|
||
|
fwu->ext_data_source = NULL;
|
||
|
fwu->image = NULL;
|
||
|
fwu->force_update = FORCE_UPDATE;
|
||
|
fwu->do_lockdown = DO_LOCKDOWN;
|
||
|
+reflash_store_exit:
|
||
|
+ mutex_unlock(&fwu_sysfs_mutex);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
@@ -3860,35 +3890,42 @@ 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->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;
|
||
|
}
|
||
|
|
||
|
@@ -3905,7 +3942,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev,
|
||
|
if (input != 1)
|
||
|
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",
|
||
|
@@ -3926,7 +3967,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;
|
||
|
}
|
||
|
@@ -3937,8 +3981,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",
|
||
|
@@ -3952,7 +4000,7 @@ static ssize_t fwu_sysfs_image_name_store(struct device *dev,
|
||
|
static ssize_t fwu_sysfs_image_size_store(struct device *dev,
|
||
|
struct device_attribute *attr, const char *buf, size_t count)
|
||
|
{
|
||
|
- int retval;
|
||
|
+ ssize_t retval;
|
||
|
unsigned long size;
|
||
|
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
|
||
|
|
||
|
@@ -3960,6 +4008,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;
|
||
|
|
||
|
@@ -3969,10 +4020,12 @@ 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;
|
||
|
+ } else {
|
||
|
+ retval = count;
|
||
|
}
|
||
|
-
|
||
|
- return count;
|
||
|
+ mutex_unlock(&fwu_sysfs_mutex);
|
||
|
+ return retval;
|
||
|
}
|
||
|
|
||
|
static ssize_t fwu_sysfs_block_size_show(struct device *dev,
|
||
|
@@ -4024,35 +4077,42 @@ 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 guest_code_store_exit;
|
||
|
}
|
||
|
|
||
|
if (input != 1) {
|
||
|
retval = -EINVAL;
|
||
|
- goto exit;
|
||
|
+ goto guest_code_store_exit;
|
||
|
}
|
||
|
|
||
|
- if (!fwu->ext_data_source)
|
||
|
- return -EINVAL;
|
||
|
- else
|
||
|
+ if (!fwu->ext_data_source) {
|
||
|
+ retval = -EINVAL;
|
||
|
+ goto 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 guest_code_store_free_exit;
|
||
|
}
|
||
|
|
||
|
retval = count;
|
||
|
|
||
|
-exit:
|
||
|
+guest_code_store_free_exit:
|
||
|
kfree(fwu->ext_data_source);
|
||
|
fwu->ext_data_source = NULL;
|
||
|
fwu->image = NULL;
|
||
|
+guest_code_store_exit:
|
||
|
+ mutex_unlock(&fwu_sysfs_mutex);
|
||
|
return retval;
|
||
|
}
|
||
|
|