[PATCH] Input: synaptics-rmi4 - reject concurrent firmware updates

Shuangpeng Bai <[email protected]>
Newsgroups org.kernel.vger.linux-input,org.kernel.vger.stable
Message-ID <[email protected]>
The update_fw sysfs store callback can execute concurrently. Each
invocation runs rmi_firmware_update(), which tears down and rebuilds the
RMI function list.

If two writes overlap, both rmi_free_function_list() calls can walk the
same list and select the same rmi_function entry. One invocation can delete
and unregister the entry while the other still uses its iterator's fn
pointer, resulting in use-after-free or list corruption. This was
reproduced as list_del corruption in rmi_free_function_list().

Firmware flashing is an exclusive operation, and running a second update
concurrently has no useful semantics. Add a per-device update_mutex and
try to acquire it immediately before starting the update. Return -EBUSY if
another update is already active, and hold the mutex until the update has
completed so their function-list teardown cannot overlap.

The status attribute does not acquire update_mutex, so update_fw_status can
still be polled while an update is running.

Fixes: 29fd0ec2bdbe ("Input: synaptics-rmi4 - add support for F34 device reflash")
Cc: [email protected]
Signed-off-by: Shuangpeng Bai <[email protected]>
---
 drivers/input/rmi4/rmi_driver.c | 1 +
 drivers/input/rmi4/rmi_f34.c    | 8 +++++---
 include/linux/rmi.h             | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 5d49a9021c7d..3a5cb17e938f 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -1218,6 +1218,7 @@ static int rmi_driver_probe(struct device *dev)
 
 	mutex_init(&data->irq_mutex);
 	mutex_init(&data->enabled_mutex);
+	mutex_init(&data->update_mutex);
 
 	retval = rmi_probe_interrupts(data);
 	if (retval)
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
index f1947f03b06a..04f12165cab0 100644
--- a/drivers/input/rmi4/rmi_f34.c
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -468,13 +468,15 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev,
 	if (error)
 		return error;
 
+	if (!mutex_trylock(&data->update_mutex))
+		return -EBUSY;
+
 	dev_info(dev, "Flashing %s\n", fw_name);
 
 	error = rmi_firmware_update(data, fw);
-	if (error)
-		return error;
 
-	return count;
+	mutex_unlock(&data->update_mutex);
+	return error ?: count;
 }
 
 static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index ab7eea01ab42..d56c23240868 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -340,6 +340,7 @@ struct rmi_driver_data {
 
 	struct rmi_function *f01_container;
 	struct rmi_function *f34_container;
+	struct mutex update_mutex;
 	bool bootloader_mode;
 
 	int num_of_irq_regs;
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.