mirror of https://github.com/torvalds/linux.git
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:
parent
c67bb84434
commit
0cc15a10c3
|
|
@ -2058,6 +2058,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
|
||||||
{
|
{
|
||||||
struct regulator_supply_alias *map;
|
struct regulator_supply_alias *map;
|
||||||
|
|
||||||
|
mutex_lock(®ulator_list_mutex);
|
||||||
map = regulator_find_supply_alias(*dev, *supply);
|
map = regulator_find_supply_alias(*dev, *supply);
|
||||||
if (map) {
|
if (map) {
|
||||||
dev_dbg(*dev, "Mapping supply %s to %s,%s\n",
|
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;
|
*dev = map->alias_dev;
|
||||||
*supply = map->alias_supply;
|
*supply = map->alias_supply;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(®ulator_list_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int regulator_match(struct device *dev, const void *data)
|
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)
|
const char *alias_id)
|
||||||
{
|
{
|
||||||
struct regulator_supply_alias *map;
|
struct regulator_supply_alias *map;
|
||||||
|
struct regulator_supply_alias *new_map;
|
||||||
|
|
||||||
map = regulator_find_supply_alias(dev, id);
|
new_map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
|
||||||
if (map)
|
if (!new_map)
|
||||||
return -EEXIST;
|
|
||||||
|
|
||||||
map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
|
|
||||||
if (!map)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
map->src_dev = dev;
|
mutex_lock(®ulator_list_mutex);
|
||||||
map->src_supply = id;
|
map = regulator_find_supply_alias(dev, id);
|
||||||
map->alias_dev = alias_dev;
|
if (map) {
|
||||||
map->alias_supply = alias_id;
|
mutex_unlock(®ulator_list_mutex);
|
||||||
|
kfree(new_map);
|
||||||
list_add(&map->list, ®ulator_supply_alias_list);
|
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, ®ulator_supply_alias_list);
|
||||||
|
mutex_unlock(®ulator_list_mutex);
|
||||||
pr_info("Adding alias for supply %s,%s -> %s,%s\n",
|
pr_info("Adding alias for supply %s,%s -> %s,%s\n",
|
||||||
id, dev_name(dev), alias_id, dev_name(alias_dev));
|
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;
|
struct regulator_supply_alias *map;
|
||||||
|
|
||||||
|
mutex_lock(®ulator_list_mutex);
|
||||||
map = regulator_find_supply_alias(dev, id);
|
map = regulator_find_supply_alias(dev, id);
|
||||||
if (map) {
|
if (map) {
|
||||||
list_del(&map->list);
|
list_del(&map->list);
|
||||||
kfree(map);
|
kfree(map);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(®ulator_list_mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
|
EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue