Skip to content

Commit ca39500

Browse files
committed
Input: synaptics-rmi - fix crash with unsupported versions of F34
Sysfs interface for updating firmware for RMI devices is available even when F34 probe fails. The code checks for presence of F34 "container" pointer and then tries to use the function data attached to the sub-device. F34 assigns the function data early, before it knows if probe will succeed, leaving behind a stale pointer. Fix this by expanding checks to not only test for presence of F34 "container" but also check if there is driver data assigned to the sub-device, and call dev_set_drvdata() only after we are certain that probe is successful. This is not a complete fix, since F34 will be freed during firmware update, so there is still a race when fetching and accessing this pointer. This race will be addressed in follow-up changes. Reported-by: Hanno Böck <[email protected]> Fixes: 29fd0ec ("Input: synaptics-rmi4 - add support for F34 device reflash") Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent f0d1794 commit ca39500

File tree

1 file changed

+76
-59
lines changed

1 file changed

+76
-59
lines changed

drivers/input/rmi4/rmi_f34.c

Lines changed: 76 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (C) 2016 Zodiac Inflight Innovations
55
*/
66

7+
#include "linux/device.h"
78
#include <linux/kernel.h>
89
#include <linux/rmi.h>
910
#include <linux/firmware.h>
@@ -289,39 +290,30 @@ static int rmi_f34_update_firmware(struct f34_data *f34,
289290
return rmi_f34_flash_firmware(f34, syn_fw);
290291
}
291292

292-
static int rmi_f34_status(struct rmi_function *fn)
293-
{
294-
struct f34_data *f34 = dev_get_drvdata(&fn->dev);
295-
296-
/*
297-
* The status is the percentage complete, or once complete,
298-
* zero for success or a negative return code.
299-
*/
300-
return f34->update_status;
301-
}
302-
303293
static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
304294
struct device_attribute *dattr,
305295
char *buf)
306296
{
307297
struct rmi_driver_data *data = dev_get_drvdata(dev);
308-
struct rmi_function *fn = data->f34_container;
298+
struct rmi_function *fn;
309299
struct f34_data *f34;
310300

311-
if (fn) {
312-
f34 = dev_get_drvdata(&fn->dev);
313-
314-
if (f34->bl_version == 5)
315-
return sysfs_emit(buf, "%c%c\n",
316-
f34->bootloader_id[0],
317-
f34->bootloader_id[1]);
318-
else
319-
return sysfs_emit(buf, "V%d.%d\n",
320-
f34->bootloader_id[1],
321-
f34->bootloader_id[0]);
322-
}
301+
fn = data->f34_container;
302+
if (!fn)
303+
return -ENODEV;
323304

324-
return 0;
305+
f34 = dev_get_drvdata(&fn->dev);
306+
if (!f34)
307+
return -ENODEV;
308+
309+
if (f34->bl_version == 5)
310+
return sysfs_emit(buf, "%c%c\n",
311+
f34->bootloader_id[0],
312+
f34->bootloader_id[1]);
313+
else
314+
return sysfs_emit(buf, "V%d.%d\n",
315+
f34->bootloader_id[1],
316+
f34->bootloader_id[0]);
325317
}
326318

327319
static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL);
@@ -334,13 +326,16 @@ static ssize_t rmi_driver_configuration_id_show(struct device *dev,
334326
struct rmi_function *fn = data->f34_container;
335327
struct f34_data *f34;
336328

337-
if (fn) {
338-
f34 = dev_get_drvdata(&fn->dev);
329+
fn = data->f34_container;
330+
if (!fn)
331+
return -ENODEV;
332+
333+
f34 = dev_get_drvdata(&fn->dev);
334+
if (!f34)
335+
return -ENODEV;
339336

340-
return sysfs_emit(buf, "%s\n", f34->configuration_id);
341-
}
342337

343-
return 0;
338+
return sysfs_emit(buf, "%s\n", f34->configuration_id);
344339
}
345340

346341
static DEVICE_ATTR(configuration_id, 0444,
@@ -356,10 +351,14 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
356351

357352
if (!data->f34_container) {
358353
dev_warn(dev, "%s: No F34 present!\n", __func__);
359-
return -EINVAL;
354+
return -ENODEV;
360355
}
361356

362357
f34 = dev_get_drvdata(&data->f34_container->dev);
358+
if (!f34) {
359+
dev_warn(dev, "%s: No valid F34 present!\n", __func__);
360+
return -ENODEV;
361+
}
363362

364363
if (f34->bl_version >= 7) {
365364
if (data->pdt_props & HAS_BSR) {
@@ -485,10 +484,18 @@ static ssize_t rmi_driver_update_fw_status_show(struct device *dev,
485484
char *buf)
486485
{
487486
struct rmi_driver_data *data = dev_get_drvdata(dev);
488-
int update_status = 0;
487+
struct f34_data *f34;
488+
int update_status = -ENODEV;
489489

490-
if (data->f34_container)
491-
update_status = rmi_f34_status(data->f34_container);
490+
/*
491+
* The status is the percentage complete, or once complete,
492+
* zero for success or a negative return code.
493+
*/
494+
if (data->f34_container) {
495+
f34 = dev_get_drvdata(&data->f34_container->dev);
496+
if (f34)
497+
update_status = f34->update_status;
498+
}
492499

493500
return sysfs_emit(buf, "%d\n", update_status);
494501
}
@@ -508,33 +515,21 @@ static const struct attribute_group rmi_firmware_attr_group = {
508515
.attrs = rmi_firmware_attrs,
509516
};
510517

511-
static int rmi_f34_probe(struct rmi_function *fn)
518+
static int rmi_f34v5_probe(struct f34_data *f34)
512519
{
513-
struct f34_data *f34;
514-
unsigned char f34_queries[9];
520+
struct rmi_function *fn = f34->fn;
521+
u8 f34_queries[9];
515522
bool has_config_id;
516-
u8 version = fn->fd.function_version;
517-
int ret;
518-
519-
f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
520-
if (!f34)
521-
return -ENOMEM;
522-
523-
f34->fn = fn;
524-
dev_set_drvdata(&fn->dev, f34);
525-
526-
/* v5 code only supported version 0, try V7 probe */
527-
if (version > 0)
528-
return rmi_f34v7_probe(f34);
523+
int error;
529524

530525
f34->bl_version = 5;
531526

532-
ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
533-
f34_queries, sizeof(f34_queries));
534-
if (ret) {
527+
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
528+
f34_queries, sizeof(f34_queries));
529+
if (error) {
535530
dev_err(&fn->dev, "%s: Failed to query properties\n",
536531
__func__);
537-
return ret;
532+
return error;
538533
}
539534

540535
snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
@@ -560,11 +555,11 @@ static int rmi_f34_probe(struct rmi_function *fn)
560555
f34->v5.config_blocks);
561556

562557
if (has_config_id) {
563-
ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
564-
f34_queries, sizeof(f34_queries));
565-
if (ret) {
558+
error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
559+
f34_queries, sizeof(f34_queries));
560+
if (error) {
566561
dev_err(&fn->dev, "Failed to read F34 config ID\n");
567-
return ret;
562+
return error;
568563
}
569564

570565
snprintf(f34->configuration_id, sizeof(f34->configuration_id),
@@ -573,12 +568,34 @@ static int rmi_f34_probe(struct rmi_function *fn)
573568
f34_queries[2], f34_queries[3]);
574569

575570
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
576-
f34->configuration_id);
571+
f34->configuration_id);
577572
}
578573

579574
return 0;
580575
}
581576

577+
static int rmi_f34_probe(struct rmi_function *fn)
578+
{
579+
struct f34_data *f34;
580+
u8 version = fn->fd.function_version;
581+
int error;
582+
583+
f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
584+
if (!f34)
585+
return -ENOMEM;
586+
587+
f34->fn = fn;
588+
589+
/* v5 code only supported version 0 */
590+
error = version == 0 ? rmi_f34v5_probe(f34) : rmi_f34v7_probe(f34);
591+
if (error)
592+
return error;
593+
594+
dev_set_drvdata(&fn->dev, f34);
595+
596+
return 0;
597+
}
598+
582599
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
583600
{
584601
return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);

0 commit comments

Comments
 (0)