Skip to content

Commit 0cc15a1

Browse files
sparkhuangbroonie
authored andcommitted
regulator: core: Protect regulator_supply_alias_list with regulator_list_mutex
regulator_supply_alias_list was accessed without any locking in regulator_supply_alias(), regulator_register_supply_alias(), and regulator_unregister_supply_alias(). Concurrent registration, unregistration and lookups can race, leading to: 1 use-after-free if an alias entry is removed while being read, 2 duplicate entries when two threads register the same alias, 3 inconsistent alias mappings observed by consumers. Protect all traversals, insertions and deletions on regulator_supply_alias_list with the existing regulator_list_mutex. Fixes: a06ccd9 ("regulator: core: Add ability to create a lookup alias for supply") Signed-off-by: sparkhuang <huangshaobo3@xiaomi.com> Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://patch.msgid.link/20251127025716.5440-1-huangshaobo3@xiaomi.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent c67bb84 commit 0cc15a1

1 file changed

Lines changed: 20 additions & 12 deletions

File tree

drivers/regulator/core.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
20582058
{
20592059
struct regulator_supply_alias *map;
20602060

2061+
mutex_lock(&regulator_list_mutex);
20612062
map = regulator_find_supply_alias(*dev, *supply);
20622063
if (map) {
20632064
dev_dbg(*dev, "Mapping supply %s to %s,%s\n",
@@ -2066,6 +2067,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
20662067
*dev = map->alias_dev;
20672068
*supply = map->alias_supply;
20682069
}
2070+
mutex_unlock(&regulator_list_mutex);
20692071
}
20702072

20712073
static int regulator_match(struct device *dev, const void *data)
@@ -2618,22 +2620,26 @@ int regulator_register_supply_alias(struct device *dev, const char *id,
26182620
const char *alias_id)
26192621
{
26202622
struct regulator_supply_alias *map;
2623+
struct regulator_supply_alias *new_map;
26212624

2622-
map = regulator_find_supply_alias(dev, id);
2623-
if (map)
2624-
return -EEXIST;
2625-
2626-
map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
2627-
if (!map)
2625+
new_map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
2626+
if (!new_map)
26282627
return -ENOMEM;
26292628

2630-
map->src_dev = dev;
2631-
map->src_supply = id;
2632-
map->alias_dev = alias_dev;
2633-
map->alias_supply = alias_id;
2634-
2635-
list_add(&map->list, &regulator_supply_alias_list);
2629+
mutex_lock(&regulator_list_mutex);
2630+
map = regulator_find_supply_alias(dev, id);
2631+
if (map) {
2632+
mutex_unlock(&regulator_list_mutex);
2633+
kfree(new_map);
2634+
return -EEXIST;
2635+
}
26362636

2637+
new_map->src_dev = dev;
2638+
new_map->src_supply = id;
2639+
new_map->alias_dev = alias_dev;
2640+
new_map->alias_supply = alias_id;
2641+
list_add(&new_map->list, &regulator_supply_alias_list);
2642+
mutex_unlock(&regulator_list_mutex);
26372643
pr_info("Adding alias for supply %s,%s -> %s,%s\n",
26382644
id, dev_name(dev), alias_id, dev_name(alias_dev));
26392645

@@ -2653,11 +2659,13 @@ void regulator_unregister_supply_alias(struct device *dev, const char *id)
26532659
{
26542660
struct regulator_supply_alias *map;
26552661

2662+
mutex_lock(&regulator_list_mutex);
26562663
map = regulator_find_supply_alias(dev, id);
26572664
if (map) {
26582665
list_del(&map->list);
26592666
kfree(map);
26602667
}
2668+
mutex_unlock(&regulator_list_mutex);
26612669
}
26622670
EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
26632671

0 commit comments

Comments
 (0)