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

Commit d376d4c8 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Input: synaptics: check input, prevent sysfs races"

parents 75f06af3 e3eb0147
Loading
Loading
Loading
Loading
+86 −10
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,39 +1590,72 @@ 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__);
		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]),
			(const void *)buf,
			count);

	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;
@@ -1650,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;
}

@@ -1660,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;
@@ -1693,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;
}

@@ -1703,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;
@@ -1726,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;
}

@@ -1742,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",
@@ -1763,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;
}
@@ -1771,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;
@@ -1794,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;
@@ -1807,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,
+86 −11
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/firmware.h>
@@ -296,6 +297,7 @@ struct synaptics_rmi4_fwu_handle {
static struct synaptics_rmi4_fwu_handle *fwu;

DECLARE_COMPLETION(fwu_remove_complete);
DEFINE_MUTEX(fwu_sysfs_mutex);

static unsigned int extract_uint(const unsigned char *ptr)
{
@@ -1680,28 +1682,47 @@ 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(&fwu_sysfs_mutex))
		return -EBUSY;

	if (count < fwu->config_size) {
		dev_err(&rmi4_data->i2c_client->dev,
				"%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(&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(&fwu_sysfs_mutex))
		return -EBUSY;
	if (!fwu->ext_data_source) {
		dev_err(&fwu->rmi4_data->i2c_client->dev,
				"Cannot use this without setting imagesize!\n");
		retval = -EAGAIN;
		goto exit;
	}
	if (count > fwu->image_size - fwu->data_pos) {
		dev_err(&fwu->rmi4_data->i2c_client->dev,
				"%s: Not enough space in buffer\n",
				__func__);
		return -EINVAL;

		retval = -EINVAL;
		goto exit;
	}

	memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
@@ -1710,8 +1731,10 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file,

	fwu->data_buffer = fwu->ext_data_source;
	fwu->data_pos += count;

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

static ssize_t fwu_sysfs_image_name_store(struct device *dev,
@@ -1734,18 +1757,29 @@ static ssize_t fwu_sysfs_image_name_store(struct device *dev,
		return -EINVAL;
	}

	if (!mutex_trylock(&fwu_sysfs_mutex))
		return -EBUSY;
	strlcpy(rmi4_data->fw_image_name, buf, count);
	mutex_unlock(&fwu_sysfs_mutex);

	return count;
}

static ssize_t fwu_sysfs_image_name_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	ssize_t retval;

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

	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
		return snprintf(buf, PAGE_SIZE, "%s\n",
		retval = snprintf(buf, PAGE_SIZE, "%s\n",
			fwu->rmi4_data->fw_image_name);
	else
		return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
		retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n");
	mutex_unlock(&fwu_sysfs_mutex);
	return retval;
}

static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
@@ -1755,6 +1789,9 @@ static ssize_t fwu_sysfs_force_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;

	retval = kstrtouint(buf, 10, &input);
	if (retval)
		goto exit;
@@ -1781,7 +1818,10 @@ exit:
	kfree(fwu->ext_data_source);
	fwu->ext_data_source = NULL;
	fwu->force_update = FORCE_UPDATE;
	fwu->image_size = 0;
	fwu->data_pos = 0;
	fwu->do_lockdown = rmi4_data->board->do_lockdown;
	mutex_unlock(&fwu_sysfs_mutex);
	return retval;
}

@@ -1792,6 +1832,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(&fwu_sysfs_mutex))
		return -EBUSY;

	retval = kstrtouint(buf, 10, &input);
	if (retval)
		goto exit;
@@ -1822,8 +1865,11 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
exit:
	kfree(fwu->ext_data_source);
	fwu->ext_data_source = NULL;
	fwu->image_size = 0;
	fwu->data_pos = 0;
	fwu->force_update = FORCE_UPDATE;
	fwu->do_lockdown = rmi4_data->board->do_lockdown;
	mutex_unlock(&fwu_sysfs_mutex);
	return retval;
}

@@ -1834,6 +1880,9 @@ static ssize_t fwu_sysfs_write_lockdown_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;
@@ -1859,6 +1908,9 @@ exit:
	fwu->ext_data_source = NULL;
	fwu->force_update = FORCE_UPDATE;
	fwu->do_lockdown = rmi4_data->board->do_lockdown;
	fwu->image_size = 0;
	fwu->data_pos = 0;
	mutex_unlock(&fwu_sysfs_mutex);
	return retval;
}

@@ -1869,6 +1921,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(&fwu_sysfs_mutex))
		return -EBUSY;

	retval = kstrtouint(buf, 10, &input);
	if (retval)
		goto exit;
@@ -1891,6 +1946,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev,
exit:
	kfree(fwu->ext_data_source);
	fwu->ext_data_source = NULL;
	fwu->image_size = 0;
	fwu->data_pos = 0;
	mutex_unlock(&fwu_sysfs_mutex);
	return retval;
}

@@ -1908,7 +1966,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->i2c_client->dev,
				"%s: Failed to read config\n",
@@ -1937,7 +1999,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
		return -EINVAL;
	}

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

	return count;
}
@@ -1952,15 +2017,23 @@ 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;

	kfree(fwu->ext_data_source);
	fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
	if (!fwu->ext_data_source)
		return -ENOMEM;
	if (!fwu->ext_data_source) {
		retval = -ENOMEM;
		goto exit;
	}

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

static ssize_t fwu_sysfs_block_size_show(struct device *dev,
@@ -2124,7 +2197,9 @@ static struct device_attribute attrs[] = {

static void synaptics_rmi4_fwu_work(struct work_struct *work)
{
	mutex_lock(&fwu_sysfs_mutex);
	fwu_start_reflash();
	mutex_unlock(&fwu_sysfs_mutex);
}

static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)