summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2020-08-31 23:43:35 +0300
committerMark Brown <broonie@kernel.org>2020-09-01 15:26:28 +0300
commit0a7416f94707c60b9f66b01c0a505b7e41375f3a (patch)
tree6df5115827f260e3ee84a4d8e218df2435743361 /drivers/regulator
parent3bec5b6aae830355e786e204b20a7cea38c3a8ed (diff)
downloadlinux-0a7416f94707c60b9f66b01c0a505b7e41375f3a.tar.xz
regulator: core: Fix slab-out-of-bounds in regulator_unlock_recursive()
The recent commit 7d8196641ee1 ("regulator: Remove pointer table overallocation") changed the size of coupled_rdevs and now KASAN is able to detect slab-out-of-bounds problem in regulator_unlock_recursive(), which is a legit problem caused by a typo in the code. The recursive unlock function uses n_coupled value of a parent regulator for unlocking supply regulator, while supply's n_coupled should be used. In practice problem may only affect platforms that use coupled regulators. Cc: stable@vger.kernel.org # 5.0+ Fixes: f8702f9e4aa7 ("regulator: core: Use ww_mutex for regulators locking") Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Link: https://lore.kernel.org/r/20200831204335.19489-1-digetx@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/core.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 6789d1efdf5d..0e764596b0c0 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -236,8 +236,8 @@ static bool regulator_supply_is_couple(struct regulator_dev *rdev)
static void regulator_unlock_recursive(struct regulator_dev *rdev,
unsigned int n_coupled)
{
- struct regulator_dev *c_rdev;
- int i;
+ struct regulator_dev *c_rdev, *supply_rdev;
+ int i, supply_n_coupled;
for (i = n_coupled; i > 0; i--) {
c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1];
@@ -245,10 +245,13 @@ static void regulator_unlock_recursive(struct regulator_dev *rdev,
if (!c_rdev)
continue;
- if (c_rdev->supply && !regulator_supply_is_couple(c_rdev))
- regulator_unlock_recursive(
- c_rdev->supply->rdev,
- c_rdev->coupling_desc.n_coupled);
+ if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
+ supply_rdev = c_rdev->supply->rdev;
+ supply_n_coupled = supply_rdev->coupling_desc.n_coupled;
+
+ regulator_unlock_recursive(supply_rdev,
+ supply_n_coupled);
+ }
regulator_unlock(c_rdev);
}