]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iio: adc: ad4695: fix out of bounds array access
authorDavid Lechner <dlechner@baylibre.com>
Tue, 18 Feb 2025 23:17:45 +0000 (17:17 -0600)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Tue, 4 Mar 2025 13:17:50 +0000 (13:17 +0000)
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 <dlechner@baylibre.com>
Reviewed-by: Trevor Gamblin <tgamblin@baylibre.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
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 <Jonathan.Cameron@huawei.com>
drivers/iio/adc/ad4695.c

index 9dbf326b627378afcc1ce387ea930b032d2354e4..d42dea494302ddaee4bbf41aac3a19f84cde45e6 100644 (file)
@@ -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);