]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iio: adc: ad_sigma_delta: fix clear_pending_event for registerless devices
authorRadu Sabau <radu.sabau@analog.com>
Wed, 27 May 2026 09:38:39 +0000 (12:38 +0300)
committerJonathan Cameron <jic23@kernel.org>
Fri, 29 May 2026 08:57:23 +0000 (09:57 +0100)
ad_sigma_delta_clear_pending_event() falls through to the status register
read path for devices with has_registers = false and no rdy_gpiod. For
such devices, ad_sd_read_reg() skips the address byte entirely and clocks
raw MISO bytes with no address phase — making it byte-for-byte identical
to reading conversion data. If a pending conversion result is present,
this partially consumes it and corrupts the data stream for the subsequent
ad_sd_read_reg() call in ad_sigma_delta_single_conversion().

Furthermore, with num_resetclks = 0 on these devices, data_read_len
evaluates to 0. If the clocked byte has bit 7 clear, pending_event is set
and the code attempts memset(data + 2, 0xff, 0 - 1), overflowing to
SIZE_MAX and corrupting the heap.

Fix by returning 0 immediately when neither rdy_gpiod nor has_registers
is set. This is safe for all current registerless devices: ad7191 and
ad7780 (with powerdown GPIO) are reset between conversions by CS
deassertion, so there is no stale result to drain; ad7780 (without
powerdown GPIO) and max11205 are continuously-converting and cycle ~DRDY
at the output data rate regardless of whether the previous result was
read, so the next falling edge fires naturally.

A future registerless device that holds ~DRDY asserted until data is read
would be broken by this early return and would require either
num_resetclks set or a rdy-gpio.

The same heap corruption is reachable on any device with rdy_gpiod set
but num_resetclks = 0: if the GPIO indicates a pending event, the drain
path executes memset(data + 2, 0xff, 0 - 1) regardless of has_registers.
Add an explicit data_read_len == 0 guard after the pending event check;
the stale result is then consumed by the first ad_sd_read_reg() call in
ad_sigma_delta_single_conversion().

Fixes: 132d44dc6966 ("iio: adc: ad_sigma_delta: Check for previous ready signals")
Signed-off-by: Radu Sabau <radu.sabau@analog.com>
Cc: <Stable@vger.kernel.org>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/adc/ad_sigma_delta.c

index 651ade67ad2e97794875872922d7d3a903b91498..1b410291da5378584347231fcdb328fa5633a68e 100644 (file)
@@ -262,11 +262,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
 
        /*
         * Read R̅D̅Y̅ pin (if possible) or status register to check if there is an
-        * old event.
+        * old event. For devices with neither an RDY GPIO nor registers,
+        * ad_sd_read_reg() transmits no address byte and clocks raw MISO bytes,
+        * which is indistinguishable from reading conversion data and would
+        * partially consume a pending result. Skip the check for such devices.
+        *
+        * This is safe for all current registerless devices: ad7191 and ad7780
+        * (with powerdown GPIO) are reset between conversions by CS deassertion,
+        * so there is no stale result to drain; ad7780 (without powerdown GPIO)
+        * and max11205 are continuously-converting and cycle ~DRDY at the output
+        * data rate regardless of whether the previous result was read, so the
+        * next falling edge fires naturally.
+        *
+        * A future registerless device that holds ~DRDY asserted until data is
+        * read would be broken by this early return and would need either
+        * num_resetclks set or a rdy-gpio.
         */
        if (sigma_delta->rdy_gpiod) {
                pending_event = gpiod_get_value(sigma_delta->rdy_gpiod);
-       } else {
+       } else if (sigma_delta->info->has_registers) {
                unsigned int status_reg;
 
                ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg);
@@ -274,11 +288,24 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
                        return ret;
 
                pending_event = !(status_reg & AD_SD_REG_STATUS_RDY);
+       } else {
+               return 0;
        }
 
        if (!pending_event)
                return 0;
 
+       /*
+        * With num_resetclks = 0, data_read_len is 0 and the drain sequence
+        * below would compute memset(data + 2, 0xff, 0 - 1), underflowing to
+        * SIZE_MAX and corrupting the heap. There is no safe way to drain the
+        * stale result without knowing the data register size; it will be
+        * consumed by the first ad_sd_read_reg() call in
+        * ad_sigma_delta_single_conversion().
+        */
+       if (!data_read_len)
+               return 0;
+
        /*
         * In general the size of the data register is unknown. It varies from
         * device to device, might be one byte longer if CONTROL.DATA_STATUS is