mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-26 03:20:34 -04:00
iio: adc: ad_sigma_delta: fix clear_pending_event for registerless devices
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: 132d44dc69 ("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>
This commit is contained in:
committed by
Jonathan Cameron
parent
c72da06885
commit
91bc6767a4
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user