Message ID | 20200722155103.979802-24-jic23@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | IIO: Fused set 1 and 2 of timestamp alignment fixes | expand |
On Wed, Jul 22, 2020 at 6:53 PM Jonathan Cameron <jic23@kernel.org> wrote: > > From: Jonathan Cameron <Jonathan.Cameron@huawei.com> > > One of a class of bugs pointed out by Lars in a recent review. > iio_push_to_buffers_with_timestamp assumes the buffer used is aligned > to the size of the timestamp (8 bytes). This is not guaranteed in > this driver which uses an array of smaller elements on the stack. > As Lars also noted this anti pattern can involve a leak of data to > userspace and that indeed can happen here. We close both issues by > moving to a suitable structure in the iio_priv() data with alignment > explicitly requested. This data is allocated with kzalloc so no > data can leak apart from previous readings. > > In this driver the timestamp can end up in various different locations > depending on what other channels are enabled. As a result, we don't > use a structure to specify it's position as that would be missleading. ... > + /* > + * Used to correctly align data. > + * Ensure timestamp is naturally aligned. > + */ > + u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8); u32 vs. u16?
On Wed, 22 Jul 2020 23:54:29 +0300 Andy Shevchenko <andy.shevchenko@gmail.com> wrote: > On Wed, Jul 22, 2020 at 6:53 PM Jonathan Cameron <jic23@kernel.org> wrote: > > > > From: Jonathan Cameron <Jonathan.Cameron@huawei.com> > > > > One of a class of bugs pointed out by Lars in a recent review. > > iio_push_to_buffers_with_timestamp assumes the buffer used is aligned > > to the size of the timestamp (8 bytes). This is not guaranteed in > > this driver which uses an array of smaller elements on the stack. > > As Lars also noted this anti pattern can involve a leak of data to > > userspace and that indeed can happen here. We close both issues by > > moving to a suitable structure in the iio_priv() data with alignment > > explicitly requested. This data is allocated with kzalloc so no > > data can leak apart from previous readings. > > > > In this driver the timestamp can end up in various different locations > > depending on what other channels are enabled. As a result, we don't > > use a structure to specify it's position as that would be missleading. > > ... > > > + /* > > + * Used to correctly align data. > > + * Ensure timestamp is naturally aligned. > > + */ > > + u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8); > > u32 vs. u16? > Curious indeed. My eyes jumped straight over that when cutting and pasting that line. I guess too big is never a problem, but should definitely tidy that up. Thanks, Jonathan
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c index 4b4fbe33930c..734ee5d82ff6 100644 --- a/drivers/iio/adc/ti-ads124s08.c +++ b/drivers/iio/adc/ti-ads124s08.c @@ -99,6 +99,11 @@ struct ads124s_private { struct gpio_desc *reset_gpio; struct spi_device *spi; struct mutex lock; + /* + * Used to correctly align data. + * Ensure timestamp is naturally aligned. + */ + u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8); u8 data[5] ____cacheline_aligned; }; @@ -269,7 +274,6 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ads124s_private *priv = iio_priv(indio_dev); - u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)]; int scan_index, j = 0; int ret; @@ -284,7 +288,7 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p) if (ret) dev_err(&priv->spi->dev, "Start ADC conversions failed\n"); - buffer[j] = ads124s_read(indio_dev, scan_index); + priv->buffer[j] = ads124s_read(indio_dev, scan_index); ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV); if (ret) dev_err(&priv->spi->dev, "Stop ADC conversions failed\n"); @@ -292,7 +296,7 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p) j++; } - iio_push_to_buffers_with_timestamp(indio_dev, buffer, + iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, pf->timestamp); iio_trigger_notify_done(indio_dev->trig);