Commit 4fd8bcec authored by Kees Cook's avatar Kees Cook Committed by Mark Brown

regulator: max77802: Bounds check regulator id against opmode

Explicitly bounds-check the id before accessing the opmode array. Seen
with GCC 13:

../drivers/regulator/max77802-regulator.c: In function 'max77802_enable':
../drivers/regulator/max77802-regulator.c:217:29: warning: array subscript [0, 41] is outside array bounds of 'unsigned int[42]' [-Warray-bounds=]
  217 |         if (max77802->opmode[id] == MAX77802_OFF_PWRREQ)
      |             ~~~~~~~~~~~~~~~~^~~~
../drivers/regulator/max77802-regulator.c:62:22: note: while referencing 'opmode'
   62 |         unsigned int opmode[MAX77802_REG_MAX];
      |                      ^~~~~~

Cc: Javier Martinez Canillas <javier@dowhile0.org>
Cc: Liam Girdwood <lgirdwood@gmail.com>
Cc: Mark Brown <broonie@kernel.org>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Acked-by: default avatarJavier Martinez Canillas <javierm@redhat.com>
Link: https://lore.kernel.org/r/20230127225203.never.864-kees@kernel.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent fad8ddda
...@@ -94,9 +94,11 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev) ...@@ -94,9 +94,11 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev)
{ {
unsigned int val = MAX77802_OFF_PWRREQ; unsigned int val = MAX77802_OFF_PWRREQ;
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev); unsigned int id = rdev_get_id(rdev);
int shift = max77802_get_opmode_shift(id); int shift = max77802_get_opmode_shift(id);
if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
return -EINVAL;
max77802->opmode[id] = val; max77802->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val << shift); rdev->desc->enable_mask, val << shift);
...@@ -110,7 +112,7 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev) ...@@ -110,7 +112,7 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev)
static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
{ {
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev); unsigned int id = rdev_get_id(rdev);
unsigned int val; unsigned int val;
int shift = max77802_get_opmode_shift(id); int shift = max77802_get_opmode_shift(id);
...@@ -127,6 +129,9 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) ...@@ -127,6 +129,9 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
return -EINVAL; return -EINVAL;
} }
if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
return -EINVAL;
max77802->opmode[id] = val; max77802->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val << shift); rdev->desc->enable_mask, val << shift);
...@@ -135,8 +140,10 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) ...@@ -135,8 +140,10 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
static unsigned max77802_get_mode(struct regulator_dev *rdev) static unsigned max77802_get_mode(struct regulator_dev *rdev)
{ {
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev); unsigned int id = rdev_get_id(rdev);
if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
return -EINVAL;
return max77802_map_mode(max77802->opmode[id]); return max77802_map_mode(max77802->opmode[id]);
} }
...@@ -160,10 +167,13 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev, ...@@ -160,10 +167,13 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev,
unsigned int mode) unsigned int mode)
{ {
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev); unsigned int id = rdev_get_id(rdev);
unsigned int val; unsigned int val;
int shift = max77802_get_opmode_shift(id); int shift = max77802_get_opmode_shift(id);
if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
return -EINVAL;
/* /*
* If the regulator has been disabled for suspend * If the regulator has been disabled for suspend
* then is invalid to try setting a suspend mode. * then is invalid to try setting a suspend mode.
...@@ -209,9 +219,11 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev, ...@@ -209,9 +219,11 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev,
static int max77802_enable(struct regulator_dev *rdev) static int max77802_enable(struct regulator_dev *rdev)
{ {
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev); unsigned int id = rdev_get_id(rdev);
int shift = max77802_get_opmode_shift(id); int shift = max77802_get_opmode_shift(id);
if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
return -EINVAL;
if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) if (max77802->opmode[id] == MAX77802_OFF_PWRREQ)
max77802->opmode[id] = MAX77802_OPMODE_NORMAL; max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
...@@ -495,7 +507,7 @@ static int max77802_pmic_probe(struct platform_device *pdev) ...@@ -495,7 +507,7 @@ static int max77802_pmic_probe(struct platform_device *pdev)
for (i = 0; i < MAX77802_REG_MAX; i++) { for (i = 0; i < MAX77802_REG_MAX; i++) {
struct regulator_dev *rdev; struct regulator_dev *rdev;
int id = regulators[i].id; unsigned int id = regulators[i].id;
int shift = max77802_get_opmode_shift(id); int shift = max77802_get_opmode_shift(id);
int ret; int ret;
...@@ -513,10 +525,12 @@ static int max77802_pmic_probe(struct platform_device *pdev) ...@@ -513,10 +525,12 @@ static int max77802_pmic_probe(struct platform_device *pdev)
* the hardware reports OFF as the regulator operating mode. * the hardware reports OFF as the regulator operating mode.
* Default to operating mode NORMAL in that case. * Default to operating mode NORMAL in that case.
*/ */
if (val == MAX77802_STATUS_OFF) if (id < ARRAY_SIZE(max77802->opmode)) {
max77802->opmode[id] = MAX77802_OPMODE_NORMAL; if (val == MAX77802_STATUS_OFF)
else max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
max77802->opmode[id] = val; else
max77802->opmode[id] = val;
}
rdev = devm_regulator_register(&pdev->dev, rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config); &regulators[i], &config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment