From: David Lechner Date: Tue, 18 Feb 2025 23:17:45 +0000 (-0600) Subject: iio: adc: ad4695: fix out of bounds array access X-Git-Tag: v6.15-rc1~78^2~8^2~52 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cafeb8a99746e218035ad000d28deeca2bad9f9c;p=thirdparty%2Fkernel%2Flinux.git iio: adc: ad4695: fix out of bounds array access Fix some out of bounds array access of st->channels_cfg in the ad4695 driver. This array only has elements for voltage channels, but it was also being accessed for the temperature channel in a few cases causing reading past the end of the array. In some cases, this was harmless because the value was read but not used. However, the in_temp_sampling_frequency attribute shares code with the in_voltageY_sampling_frequency attributes and was trying to read the oversampling ratio from the st->channels_cfg array. This resulted in a garbage value being used in the calculation and the resulting in_temp_sampling_frequency value was incorrect. To fix, make sure we always check that we are dealing with a voltage channel before accessing the st->channels_cfg array and use an oversampling ratio of 1 for the temperature channel (multiplicative identity value) since that channel doesn't support oversampling. Fixes: 67d63185db79 ("iio: adc: ad4695: add offload-based oversampling support") Signed-off-by: David Lechner Reviewed-by: Trevor Gamblin Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250218-iio-adc-ad4695-fix-out-of-bounds-array-access-v1-1-57fef8c7a3fd@baylibre.com Signed-off-by: Jonathan Cameron --- diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c index 9dbf326b62737..d42dea494302d 100644 --- a/drivers/iio/adc/ad4695.c +++ b/drivers/iio/adc/ad4695.c @@ -1054,12 +1054,14 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, { struct ad4695_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; - struct ad4695_channel_config *cfg = &st->channels_cfg[chan->scan_index]; - unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio; + struct ad4695_channel_config *cfg; unsigned int reg_val; int ret, tmp; u8 realbits; + if (chan->type == IIO_VOLTAGE) + cfg = &st->channels_cfg[chan->scan_index]; + scan_type = iio_get_current_scan_type(indio_dev, chan); if (IS_ERR(scan_type)) return PTR_ERR(scan_type); @@ -1140,7 +1142,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, tmp = sign_extend32(reg_val, 15); - switch (osr) { + switch (cfg->oversampling_ratio) { case 1: *val = tmp / 4; *val2 = abs(tmp) % 4 * MICRO / 4; @@ -1180,6 +1182,10 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, } case IIO_CHAN_INFO_SAMP_FREQ: { struct pwm_state state; + unsigned int osr = 1; + + if (chan->type == IIO_VOLTAGE) + osr = cfg->oversampling_ratio; ret = pwm_get_state_hw(st->cnv_pwm, &state); if (ret) @@ -1272,7 +1278,10 @@ static int __ad4695_write_raw(struct iio_dev *indio_dev, { struct ad4695_state *st = iio_priv(indio_dev); unsigned int reg_val; - unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio; + unsigned int osr = 1; + + if (chan->type == IIO_VOLTAGE) + osr = st->channels_cfg[chan->scan_index].oversampling_ratio; switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: @@ -1383,7 +1392,10 @@ static int ad4695_read_avail(struct iio_dev *indio_dev, }, }; struct ad4695_state *st = iio_priv(indio_dev); - unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio; + unsigned int osr = 1; + + if (chan->type == IIO_VOLTAGE) + osr = st->channels_cfg[chan->scan_index].oversampling_ratio; switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: @@ -1738,7 +1750,7 @@ static int ad4695_probe_spi_offload(struct iio_dev *indio_dev, for (i = 0; i < indio_dev->num_channels; i++) { struct iio_chan_spec *chan = &st->iio_chan[i]; - struct ad4695_channel_config *cfg = &st->channels_cfg[i]; + struct ad4695_channel_config *cfg; /* * NB: When using offload support, all channels need to have the @@ -1759,6 +1771,8 @@ static int ad4695_probe_spi_offload(struct iio_dev *indio_dev, if (chan->type != IIO_VOLTAGE) continue; + cfg = &st->channels_cfg[i]; + chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);