Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a467624a authored by Dmitry Osipenko's avatar Dmitry Osipenko Committed by Greg Kroah-Hartman
Browse files

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: f8702f9e ("regulator: core: Use ww_mutex for regulators locking")
Signed-off-by: default avatarDmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20200831204335.19489-1-digetx@gmail.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent dfbb9cea
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -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);
	}