Skip to content

Commit 20117c9

Browse files
dianderslag-linaro
authored andcommitted
mfd: core: Add locking around 'mfd_of_node_list'
Manipulating a list in the kernel isn't safe without some sort of mutual exclusion. Add a mutex any time we access / modify 'mfd_of_node_list' to prevent possible crashes. Cc: stable@vger.kernel.org Fixes: 466a62d ("mfd: core: Make a best effort attempt to match devices with the correct of_nodes") Signed-off-by: Douglas Anderson <dianders@chromium.org> Link: https://patch.msgid.link/20251210113002.1.I6ceaca2cfb7eb25737012b166671f516696be4fd@changeid Signed-off-by: Lee Jones <lee@kernel.org>
1 parent a71fee8 commit 20117c9

1 file changed

Lines changed: 22 additions & 14 deletions

File tree

drivers/mfd/mfd-core.c

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/regulator/consumer.h>
2323

2424
static LIST_HEAD(mfd_of_node_list);
25+
static DEFINE_MUTEX(mfd_of_node_mutex);
2526

2627
struct mfd_of_node_entry {
2728
struct list_head list;
@@ -104,9 +105,11 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
104105
u64 of_node_addr;
105106

106107
/* Skip if OF node has previously been allocated to a device */
107-
list_for_each_entry(of_entry, &mfd_of_node_list, list)
108-
if (of_entry->np == np)
109-
return -EAGAIN;
108+
scoped_guard(mutex, &mfd_of_node_mutex) {
109+
list_for_each_entry(of_entry, &mfd_of_node_list, list)
110+
if (of_entry->np == np)
111+
return -EAGAIN;
112+
}
110113

111114
if (!cell->use_of_reg)
112115
/* No of_reg defined - allocate first free compatible match */
@@ -128,7 +131,8 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
128131

129132
of_entry->dev = &pdev->dev;
130133
of_entry->np = np;
131-
list_add_tail(&of_entry->list, &mfd_of_node_list);
134+
scoped_guard(mutex, &mfd_of_node_mutex)
135+
list_add_tail(&of_entry->list, &mfd_of_node_list);
132136

133137
of_node_get(np);
134138
device_set_node(&pdev->dev, of_fwnode_handle(np));
@@ -284,11 +288,13 @@ static int mfd_add_device(struct device *parent, int id,
284288
if (cell->swnode)
285289
device_remove_software_node(&pdev->dev);
286290
fail_of_entry:
287-
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
288-
if (of_entry->dev == &pdev->dev) {
289-
list_del(&of_entry->list);
290-
kfree(of_entry);
291-
}
291+
scoped_guard(mutex, &mfd_of_node_mutex) {
292+
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
293+
if (of_entry->dev == &pdev->dev) {
294+
list_del(&of_entry->list);
295+
kfree(of_entry);
296+
}
297+
}
292298
fail_alias:
293299
regulator_bulk_unregister_supply_alias(&pdev->dev,
294300
cell->parent_supplies,
@@ -358,11 +364,13 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
358364
if (cell->swnode)
359365
device_remove_software_node(&pdev->dev);
360366

361-
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
362-
if (of_entry->dev == &pdev->dev) {
363-
list_del(&of_entry->list);
364-
kfree(of_entry);
365-
}
367+
scoped_guard(mutex, &mfd_of_node_mutex) {
368+
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
369+
if (of_entry->dev == &pdev->dev) {
370+
list_del(&of_entry->list);
371+
kfree(of_entry);
372+
}
373+
}
366374

367375
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
368376
cell->num_parent_supplies);

0 commit comments

Comments
 (0)