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: a06ccd9c37 ("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>
This commit is contained in:
sparkhuang 2025-11-27 10:57:16 +08:00 committed by Mark Brown
parent c67bb84434
commit 0cc15a10c3
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 20 additions and 12 deletions

View File

@ -2058,6 +2058,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
{
struct regulator_supply_alias *map;
mutex_lock(&regulator_list_mutex);
map = regulator_find_supply_alias(*dev, *supply);
if (map) {
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)
*dev = map->alias_dev;
*supply = map->alias_supply;
}
mutex_unlock(&regulator_list_mutex);
}
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,
const char *alias_id)
{
struct regulator_supply_alias *map;
struct regulator_supply_alias *new_map;
map = regulator_find_supply_alias(dev, id);
if (map)
return -EEXIST;
map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
if (!map)
new_map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
if (!new_map)
return -ENOMEM;
map->src_dev = dev;
map->src_supply = id;
map->alias_dev = alias_dev;
map->alias_supply = alias_id;
list_add(&map->list, &regulator_supply_alias_list);
mutex_lock(&regulator_list_mutex);
map = regulator_find_supply_alias(dev, id);
if (map) {
mutex_unlock(&regulator_list_mutex);
kfree(new_map);
return -EEXIST;
}
new_map->src_dev = dev;
new_map->src_supply = id;
new_map->alias_dev = alias_dev;
new_map->alias_supply = alias_id;
list_add(&new_map->list, &regulator_supply_alias_list);
mutex_unlock(&regulator_list_mutex);
pr_info("Adding alias for supply %s,%s -> %s,%s\n",
id, dev_name(dev), alias_id, dev_name(alias_dev));
@ -2653,11 +2659,13 @@ void regulator_unregister_supply_alias(struct device *dev, const char *id)
{
struct regulator_supply_alias *map;
mutex_lock(&regulator_list_mutex);
map = regulator_find_supply_alias(dev, id);
if (map) {
list_del(&map->list);
kfree(map);
}
mutex_unlock(&regulator_list_mutex);
}
EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);