Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae39f47e authored by Andrew Chant's avatar Andrew Chant Committed by Himanshu Aggarwal
Browse files

Input: synaptics: check input, prevent sysfs races



concurrent sysfs calls on the fw updater can cause
ugly race conditions.  Return EBUSY on concurrent sysfs calls.

For sysfs calls which generate deferred work, prevent
the deferred work from running concurrently with other
sysfs calls.

Also check that ext_data_source is appropriately sized
and allocated, based on a patch by
Gengjia Chen (chengjia4574@gmail.com).

Signed-off-by: default avatarAndrew Chant <achant@google.com>
Change-Id:I5bbe4992f3fd2d23db288296eaeb61f5831098e9
Bug: 30799828
Bug: 31252388
Git-repo: https://android.googlesource.com/kernel/msm.git


Git-commit: 287ce2ccfefe68067c1f9f5175b6664bf7397fe6
Signed-off-by: default avatarSrinivasa Rao Kuppala <srkupp@codeaurora.org>
parent 0380dc86
Loading
Loading
Loading
Loading
+80 −11
Original line number Diff line number Diff line
@@ -358,6 +358,7 @@ static struct device_attribute attrs[] = {
static struct synaptics_rmi4_fwu_handle *fwu;

DECLARE_COMPLETION(fwu_dsx_remove_complete);
DEFINE_MUTEX(dsx_fwu_sysfs_mutex);

static unsigned int extract_uint_le(const unsigned char *ptr)
{
@@ -1589,28 +1590,49 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file,
		char *buf, loff_t pos, size_t count)
{
	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
	ssize_t retval;

	if (!mutex_trylock(&dsx_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;
	}

	memcpy(buf, fwu->read_config_buf, fwu->config_size);

	return fwu->config_size;
	retval = fwu->config_size;
show_image_exit:
	mutex_unlock(&dsx_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)
{
	ssize_t retval;

	if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
		return -EBUSY;

	if (count > (fwu->image_size - fwu->data_pos)) {
		dev_err(fwu->rmi4_data->pdev->dev.parent,
				"%s: Not enough space in buffer\n",
				__func__);
		return -EINVAL;
		retval = -EINVAL;
		goto exit;
	}

	if (!fwu->ext_data_source) {
		dev_err(fwu->rmi4_data->pdev->dev.parent,
				"%s: Need to set imagesize\n",
				__func__);
		retval = -EINVAL;
		goto exit;
	}

	memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
@@ -1619,16 +1641,21 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file,

	fwu->data_pos += count;

exit:
	mutex_unlock(&dsx_fwu_sysfs_mutex);
	return count;
}

static ssize_t fwu_sysfs_force_reflash_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(&dsx_fwu_sysfs_mutex))
		return -EBUSY;

	if (sscanf(buf, "%u", &input) != 1) {
		retval = -EINVAL;
		goto exit;
@@ -1657,6 +1684,9 @@ exit:
	fwu->ext_data_source = NULL;
	fwu->force_update = FORCE_UPDATE;
	fwu->do_lockdown = DO_LOCKDOWN;
	fwu->data_pos = 0;
	fwu->image_size = 0;
	mutex_unlock(&dsx_fwu_sysfs_mutex);
	return retval;
}

@@ -1667,6 +1697,9 @@ 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(&dsx_fwu_sysfs_mutex))
		return -EBUSY;

	if (sscanf(buf, "%u", &input) != 1) {
		retval = -EINVAL;
		goto exit;
@@ -1700,6 +1733,9 @@ exit:
	fwu->ext_data_source = NULL;
	fwu->force_update = FORCE_UPDATE;
	fwu->do_lockdown = DO_LOCKDOWN;
	fwu->data_pos = 0;
	fwu->image_size = 0;
	mutex_unlock(&dsx_fwu_sysfs_mutex);
	return retval;
}

@@ -1710,6 +1746,9 @@ 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(&dsx_fwu_sysfs_mutex))
		return -EBUSY;

	if (sscanf(buf, "%u", &input) != 1) {
		retval = -EINVAL;
		goto exit;
@@ -1733,6 +1772,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev,
exit:
	kfree(fwu->ext_data_source);
	fwu->ext_data_source = NULL;
	fwu->data_pos = 0;
	fwu->image_size = 0;
	mutex_unlock(&dsx_fwu_sysfs_mutex);
	return retval;
}

@@ -1749,7 +1791,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev,
	if (input != 1)
		return -EINVAL;

	if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
		return -EBUSY;
	retval = fwu_do_read_config();
	mutex_unlock(&dsx_fwu_sysfs_mutex);

	if (retval < 0) {
		dev_err(rmi4_data->pdev->dev.parent,
				"%s: Failed to read config\n",
@@ -1770,7 +1816,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
	if (retval)
		return retval;

	if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
		return -EBUSY;
	fwu->config_area = config_area;
	mutex_unlock(&dsx_fwu_sysfs_mutex);

	return count;
}
@@ -1778,17 +1827,30 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
static ssize_t fwu_sysfs_image_name_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	ssize_t retval;

	if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
		return -EBUSY;
	if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0)
		return snprintf(buf, PAGE_SIZE, "%s\n",
		retval = snprintf(buf, PAGE_SIZE, "%s\n",
					fwu->rmi4_data->fw_name);
	else
		return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
		retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n");
	mutex_unlock(&dsx_fwu_sysfs_mutex);
	return retval;
}

static ssize_t fwu_sysfs_image_name_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	if (sscanf(buf, "%s", fwu->image_name) != 1)
	ssize_t retval;

	if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
		return -EBUSY;
	retval = sscanf(buf, "%49s", fwu->image_name);
	mutex_unlock(&dsx_fwu_sysfs_mutex);

	if (retval != 1)
		return -EINVAL;

	return count;
@@ -1801,9 +1863,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev,
	unsigned long size;
	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;

	if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
		return -EBUSY;

	retval = sstrtoul(buf, 10, &size);
	if (retval)
		return retval;
		goto exit;

	fwu->image_size = size;
	fwu->data_pos = 0;
@@ -1814,10 +1879,14 @@ 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;
		goto exit;
	}

	return count;
	retval = count;
exit:
	mutex_unlock(&dsx_fwu_sysfs_mutex);
	return retval;
}

static ssize_t fwu_sysfs_block_size_show(struct device *dev,