]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
regulator: core: Protect regulator_supply_alias_list with regulator_list_mutex
authorsparkhuang <huangshaobo3@xiaomi.com>
Thu, 27 Nov 2025 02:57:16 +0000 (10:57 +0800)
committerMark Brown <broonie@kernel.org>
Thu, 27 Nov 2025 18:58:26 +0000 (18:58 +0000)
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: a06ccd9c3785f ("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>
drivers/regulator/core.c

index 53b2b2d3746f9f2419234912d49bd8b4f21a893d..f4987f54e01bc2f00d780b17ac56b7f17260102d 100644 (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);