diff options
| author | Dmitry Osipenko <digetx@gmail.com> | 2020-08-31 23:43:35 +0300 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-09-17 13:47:52 +0200 |
| commit | a467624aef02df2a8d7d6dc7b0b3625c8133b6b0 (patch) | |
| tree | 88ba81e4665c7726558ca1fa27737a7877c30f12 | |
| parent | dfbb9cea5a4b07f6a5445d2f821041aae50b7632 (diff) | |
| download | linux-a467624aef02df2a8d7d6dc7b0b3625c8133b6b0.tar.gz linux-a467624aef02df2a8d7d6dc7b0b3625c8133b6b0.tar.bz2 linux-a467624aef02df2a8d7d6dc7b0b3625c8133b6b0.zip | |
regulator: core: Fix slab-out-of-bounds in regulator_unlock_recursive()
commit 0a7416f94707c60b9f66b01c0a505b7e41375f3a upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/regulator/core.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f3658ae049c5..55fc80de5ef1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -235,8 +235,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]; @@ -244,10 +244,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); } |
