Skip to contentSkip to conversation

IIO: Fused set 1 and 2 of timestamp alignment fixes

PATCH Applied Jonathan Cameron 7 participants 54 messages Jun 7, 2020 – Jul 22, 2020

Subsystems (6)

v2 of 4 Applied Latest is v4 →

lore
Share & tools
lore

Jonathan Cameron

author maintainer
#0 lore raw

v2 cover IIO: Fused set 1 and 2 of timestamp alignment fixes

From: Jonathan Cameron <[email protected]>

There are still a few more drivers to do after this, but this set with the remains of the original series 1 and 2 is big enough to keep us busy for now!

Note checkpatch really doesn't like cases of __aligned(8) as it thinks they are an extern in a c file for some reason.

A few notes based on questions on v1.

1. Why not use put_unaligned to avoid the whole thing? This interface can pass directly to a variety of in kernel users who would reasonably assume that we have true natural alignment. When it gets passed directly is subtle as it depends on whether the demux has to realign the data or not. So enabling an extra channel could result in a previously working alignment no longer being true.

Even if this is fine for existing usecases we are likely to store up subtle long term issues if we don't fix it explicitly. It's also worth noting that the data channel sometimes suffered the same problem as the timestamp.

2. Why not specify explicit padding?
In my view this is error prone in comparisom with relying on c to do the hard work for us.

3. Why not move the timestamp to the start?
ABI breakage and as timestamp is optional (no obvious from the iio_push_to_buffers_with_timestamp call) we can end up having to shift the rest of the data within that call.

Changes since v1.

Andy Schevchenko pointed out that on x86_32 s64 elements are only aligned to 4 bytes. Where I had tried to use a structure to avoid explicit need to list the padding, there were some cases where this results in insufficient padding being inserted.

This doesn't affect the few patches that had already been applied and sent upstream. (which was lucky ;)

The fix was to take advantage of __aligned(8) which (according to my reading of the c spec and the gcc docs) enforces the alignment of both the element within a structure and the structure itself. The kernel now requires a recent enough version of GCC to ensure this works both on the stack and heap. This is done in lots of other userspace interfaces. In some cases iio_push_to_buffers_with_ts is aligning data for passing to userspace, be it via a kfifo so it is sensible we should use the same solution.

Note that we could have used u64_aligned but there is no equivalent for s64 and explicit use of __aligned(8) is common in the kernel so we adopt this here.

Note that there were about 8 drivers that would have been broken with v1 of the patch. I have also forced alignment of timestamps in cases where (mostly by coincidence) we would have been fine (padding was less than 4 bytes anyway. I did this partly to reduce fragility if other elements are added in future and also to avoid cut and paste errors in new drivers.

There were a few other minor tidying up changes inline with reviews of v1.

I've kept tags given for v1 on basis the changes are minor. Shout if you disagree.

Version 1 part 1 cover letter.

Lars noted in a recent review [1] of the adis16475 that we had an issue around the alignment requirements of iio_push_to_buffers_with_timestamp. Whilst it's not documented, that function assumes that the overall buffer is 8 byte aligned, to ensure the timestamp is itself naturally aligned. We have drivers that use arrays (typically on the stack) that do not guarantee this alignment.

We could have fixed this by using a put_unaligned to write the timestamp but I think that just pushes the problem down the line. If we were to have a consumer buffer wanting all the channels in the current active_scanmask then it will get the raw buffer from the driver passed straight through. It seems odd to me if we allow passing a buffer that is not naturally aligned through to a consumer.
Hence I'm proposing to fix up all existing drivers that might pass a buffer with insufficient alignment guarantees.
Sometimes the timestamp is guaranteed to be in a particular location, in which case we can use C structure alignment guarantees to fix this in a nice readable fashion. In other cases, the timestamp location depends on which channels are enabled, and in those case we can use explicit alignment __aligned(8) to ensure the whole array is appropriately aligned.

Lars-Peter also noted that, in many of these cases, there are holes in the stack array that we never write. Those provide a potential leak of kernel data to userspace. For drivers where this applies we either need to zero those holes each time, or allocate the buffer on the heap (only once), ensuring it is zeroed at that time. We may leak previous values from the sensor but currently that seems unlikely to present any form of security risk.

As such, this first set contains a mixture of fixes. Where there are no possible holes, the buffer is kept on the stack but a c structure is used to guarantee appropriate alignment. Where there are holes, the buffer is moved into the iio_priv() accessed data private structure. A c structure or __aligned(8) is used as appropriate.

I've stopped at this point rather than doing all the drivers Lars found in order to both throttle the review burden and also to see find any general problems with the fixes before doign futher similar series. A few of the remaining ones will be rather more complex to deal with.

These have been there a long time, so whilst they are fixes we will want in stable I'm not that bothered if it takes us a little while to get them there!

[1] https://www.spinics.net/lists/devicetree/msg350590.html
[2] https://patchwork.kernel.org/cover/11554215/

Jonathan Cameron (32):
iio: accel: kxsd9: Fix alignment of local buffer. iio:accel:mma8452: Fix timestamp alignment and prevent data leak. iio:accel:bmc150-accel: Fix timestamp alignment and prevent data leak. iio:accel:mma7455: Fix timestamp alignment and prevent data leak. iio:gyro:itg3200: Fix timestamp alignment and prevent data leak. iio:proximity:mb1232: Fix timestamp alignment and prevent data leak. iio:chemical:ccs811: Fix timestamp alignment and prevent data leak. iio:light:si1145: Fix timestamp alignment and prevent data leak. iio:light:max44000 Fix timestamp alignment and prevent data leak. iio:light:rpr0521 Fix timestamp alignment and prevent data leak. iio:light:st_uvis25 Fix timestamp alignment and prevent data leak. iio:light:ltr501 Fix timestamp alignment issue. iio:magnetometer:ak8974: Fix alignment and data leak issues iio:magnetometer:ak8975 Fix alignment and data leak issues. iio:magnetometer:mag3110 Fix alignment and data leak issues. iio:humidity:hdc100x Fix alignment and data leak issues iio:humidity:hts221 Fix alignment and data leak issues iio:imu:bmi160 Fix alignment and data leak issues iio:imu:st_lsm6dsx Fix alignment and data leak issues iio:imu:inv_mpu6050 Fix dma and ts alignment and data leak issues. iio:pressure:ms5611 Fix buffer element alignment iio:pressure:mpl3115 Force alignment of buffer iio:adc:ti-adc081c Fix alignment and data leak issues iio:adc:ti-adc084s021 Fix alignment and data leak issues. iio:adc:ti-adc084s021 Tidy up endian types iio:adc:ti-ads1015 Fix buffer element alignment iio:adc:ti-ads124s08 Fix alignment and data leak issues. iio:adc:ti-ads8688 Fix alignment and potential data leak issue iio:adc:ti-adc0832 Fix alignment issue with timestamp iio:adc:ti-adc12138 Fix alignment issue with timestamp iio:adc:ina2xx Fix timestamp alignment issue. iio:adc:max1118 Fix alignment of timestamp and data leak issues

 drivers/iio/accel/bmc150-accel-core.c         | 15 ++++++--
 drivers/iio/accel/kxsd9.c                     | 16 ++++++---
 drivers/iio/accel/mma7455_core.c              | 16 ++++++---
 drivers/iio/accel/mma8452.c                   | 11 ++++--
 drivers/iio/adc/ina2xx-adc.c                  |  8 ++---
 drivers/iio/adc/max1118.c                     | 10 ++++--
 drivers/iio/adc/ti-adc081c.c                  | 11 ++++--
 drivers/iio/adc/ti-adc0832.c                  |  7 ++--
 drivers/iio/adc/ti-adc084s021.c               | 20 ++++++-----
 drivers/iio/adc/ti-adc12138.c                 |  9 ++---
 drivers/iio/adc/ti-ads1015.c                  | 12 ++++---
 drivers/iio/adc/ti-ads124s08.c                | 10 ++++--
 drivers/iio/adc/ti-ads8688.c                  | 12 +++++--
 drivers/iio/chemical/ccs811.c                 | 13 ++++---
 drivers/iio/gyro/itg3200_buffer.c             | 15 +++++---
 drivers/iio/humidity/hdc100x.c                | 10 ++++--
 drivers/iio/humidity/hts221.h                 |  7 ++--
 drivers/iio/humidity/hts221_buffer.c          |  9 ++---
 drivers/iio/imu/bmi160/bmi160.h               |  2 ++
 drivers/iio/imu/bmi160/bmi160_core.c          |  5 ++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  8 +++--
 drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    | 12 +++----
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  5 +++
 .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c    | 36 ++++++++++---------
 drivers/iio/light/ltr501.c                    | 15 ++++----
 drivers/iio/light/max44000.c                  | 12 ++++---
 drivers/iio/light/rpr0521.c                   | 17 ++++++---
 drivers/iio/light/si1145.c                    |  7 ++--
 drivers/iio/light/st_uvis25.h                 |  5 +++
 drivers/iio/light/st_uvis25_core.c            |  6 ++--
 drivers/iio/magnetometer/ak8974.c             | 10 ++++--
 drivers/iio/magnetometer/ak8975.c             | 20 +++++++----
 drivers/iio/magnetometer/mag3110.c            | 13 ++++---
 drivers/iio/pressure/mpl3115.c                |  3 +-
 drivers/iio/pressure/ms5611_core.c            | 11 ++++--
 drivers/iio/proximity/mb1232.c                | 17 ++++-----
 36 files changed, 275 insertions(+), 140 deletions(-)
Signature · 1 line
2.26.2
author maintainer
#1 lore raw

PATCH v2 1/32 iio: accel: kxsd9: Fix alignment of local buffer.

From: Jonathan Cameron <[email protected]>

iio_push_to_buffers_with_timestamp assumes 8 byte alignment which is not guaranteed by an array of smaller elements.

Note that whilst in this particular case the alignment forcing of the ts element is not strictly necessary it acts as good documentation.

---
 drivers/iio/accel/kxsd9.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/iio/accel/kxsd9.c +11 -5
index 63b1d8ee6c6f..85e3c46494d3 100644
@@ -209,14 +209,20 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
 	const struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct kxsd9_state *st = iio_priv(indio_dev);
+	/*
+	 * Ensure correct positioning and alignment of timestamp.
+	 * No need to zero initialize as all elements written.
+	 */
+	struct {
+		__be16 chan[4];
+		s64 ts __aligned(8);
+	} hw_values;
 	int ret;
-	/* 4 * 16bit values AND timestamp */
-	__be16 hw_values[8];
 
 	ret = regmap_bulk_read(st->map,
 			       KXSD9_REG_X,
-			       &hw_values,
-			       8);
+			       hw_values.chan,
+			       sizeof(hw_values.chan));
 	if (ret) {
 		dev_err(st->dev,
 			"error reading data\n");
@@ -224,7 +230,7 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev,
-					   hw_values,
+					   &hw_values,
 					   iio_get_time_ns(indio_dev));
 	iio_trigger_notify_done(indio_dev->trig);
 
Signature · 1 line
2.26.2
#2 lore raw

Re: [PATCH 01/32] iio: accel: kxsd9: Fix alignment of local buffer.

Quoted 9 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

iio_push_to_buffers_with_timestamp assumes 8 byte alignment which is not guaranteed by an array of smaller elements.

Note that whilst in this particular case the alignment forcing of the ts element is not strictly necessary it acts as good documentation.

...

drivers/iio/accel/kxsd9.c static irqreturn_t kxsd9_trigger_handler(int irq, void *p) · line 219

Quoted 4 lines
drivers/iio/accel/kxsd9.c +4 -0
+       struct {
+               __be16 chan[4];
+               s64 ts __aligned(8);
+       } hw_values;

I'm not sure what __aligned can do better here? It's naturally will be 8 alignment (struct itself due to s64 followed by 4*__be16).

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#3 lore raw

Re: [PATCH 01/32] iio: accel: kxsd9: Fix alignment of local buffer.

Quoted 13 lines · On Sun, 7 Jun 2020 19:05:15 +0300 Andy Shevchenko <[email protected]>…
Quoted 9 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

iio_push_to_buffers_with_timestamp assumes 8 byte alignment which is not guaranteed by an array of smaller elements.

Note that whilst in this particular case the alignment forcing of the ts element is not strictly necessary it acts as good documentation.

...

Quoted 8 lines

drivers/iio/accel/kxsd9.c static irqreturn_t kxsd9_trigger_handler(int irq, void *p) · line 219

Quoted 4 lines
drivers/iio/accel/kxsd9.c +4 -0
+       struct {
+               __be16 chan[4];
+               s64 ts __aligned(8);
+       } hw_values;  

I'm not sure what __aligned can do better here? It's naturally will be 8 alignment (struct itself due to s64 followed by 4*__be16).

Mainly I put it in all cases even when not needed to ensure that copy and paste versions keep the alignment statement. Here I agree it does nothing but if someone adds another channel to a driver they might miss that they also need to then add the __aligned(8) for the timestamp.

Jonathan

author maintainer
#4 lore raw

PATCH v2 2/32 iio:accel:mma8452: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte u8 array 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 ensured by use of an explicit c structure. This data is allocated with kzalloc so no data can leak appart from previous readings.

The additional forcing of the 8 byte alignment of the timestamp is not strictly necessary but makes the code less fragile by making this explicit.

Fixes c7eeea93ac60 ("iio: Add Freescale MMA8452Q 3-axis accelerometer driver")
Cc Peter Meerwald <[email protected]>
---
 drivers/iio/accel/mma8452.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/iio/accel/mma8452.c +8 -3
index ef3df402fc3c..e58fcc3741c4 100644
@@ -110,6 +110,12 @@ struct mma8452_data {
 	int sleep_val;
 	struct regulator *vdd_reg;
 	struct regulator *vddio_reg;
+
+	/* Ensure correct alignment of time stamp when present */
+	struct {
+		__be16 channels[3];
+		s64 ts __aligned(8);
+	} buffer;
 };
 
  /**
@@ -1091,14 +1097,13 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mma8452_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
 	int ret;
 
-	ret = mma8452_read(data, (__be16 *)buffer);
+	ret = mma8452_read(data, data->buffer.channels);
 	if (ret < 0)
 		goto done;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
 					   iio_get_time_ns(indio_dev));
 
 done:
Signature · 1 line
2.26.2
author maintainer
#5 lore raw

PATCH v2 3/32 iio:accel:bmc150-accel: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte 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 ensured by use of an explicit c structure. This data is allocated with kzalloc so no data can leak appart from previous readings.

Fixes tag is beyond some major refactoring so likely manual backporting would be needed to get that far back.

Whilst the force alignment of the ts is not strictly necessary, it does make the code less fragile.

Fixes 3bbec9773389 ("iio: bmc150_accel: add support for hardware fifo")
Cc Srinivas Pandruvada <[email protected]>
---
 drivers/iio/accel/bmc150-accel-core.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/iio/accel/bmc150-accel-core.c +12 -3
index 8f60d0727ee8..049f2632cf7a 100644
@@ -189,6 +189,14 @@ struct bmc150_accel_data {
 	struct mutex mutex;
 	u8 fifo_mode, watermark;
 	s16 buffer[8];
+	/*
+	 * Ensure there is sufficient space and correct alignment for
+	 * the timestamp if enabled
+	 */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 	u8 bw_bits;
 	u32 slope_dur;
 	u32 slope_thres;
@@ -922,15 +930,16 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
 	 * now.
 	 */
 	for (i = 0; i < count; i++) {
-		u16 sample[8];
 		int j, bit;
 
 		j = 0;
 		for_each_set_bit(bit, indio_dev->active_scan_mask,
 				 indio_dev->masklength)
-			memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
+			memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
+			       2);
 
-		iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
+		iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+						   tstamp);
 
 		tstamp += sample_period;
 	}
Signature · 1 line
2.26.2
#6 lore raw

Re: [PATCH 03/32] iio:accel:bmc150-accel: Fix timestamp alignment and prevent data leak.

Quoted 18 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte 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 ensured by use of an explicit c structure. This data is allocated with kzalloc so no data can leak appart from previous readings.

Fixes tag is beyond some major refactoring so likely manual backporting would be needed to get that far back.

Whilst the force alignment of the ts is not strictly necessary, it does make the code less fragile.

...

drivers/iio/accel/bmc150-accel-core.c static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, · line 939

Quoted 2 lines
drivers/iio/accel/bmc150-accel-core.c +2 -0
+                       memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
+                              2);

sizeof() ?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#7 lore raw

PATCH v2 4/32 iio:accel:mma7455: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte u8 array 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 ensured by use of an explicit c structure. This data is allocated with kzalloc so no data can leak appart from previous readings.

The force alignment of ts is not strictly necessary in this particularly case but does make the code less fragile.

Fixes a84ef0d181d9 ("iio: accel: add Freescale MMA7455L/MMA7456L 3-axis accelerometer driver")
---
 drivers/iio/accel/mma7455_core.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/iio/accel/mma7455_core.c +12 -4
index 7e99bcb3398d..922bd38ff6ea 100644
@@ -52,6 +52,14 @@
 
 struct mma7455_data {
 	struct regmap *regmap;
+	/*
+	 * Used to reorganize data.  Will ensure correct alignment of
+	 * the timestamp if present
+	 */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static int mma7455_drdy(struct mma7455_data *mma7455)
@@ -82,19 +90,19 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mma7455_data *mma7455 = iio_priv(indio_dev);
-	u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
 	int ret;
 
 	ret = mma7455_drdy(mma7455);
 	if (ret)
 		goto done;
 
-	ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
-			       sizeof(__le16) * 3);
+	ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL,
+			       mma7455->scan.channels,
+			       sizeof(mma7455->scan.channels));
 	if (ret)
 		goto done;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan,
 					   iio_get_time_ns(indio_dev));
 
 done:
Signature · 1 line
2.26.2
author maintainer
#8 lore raw

PATCH v2 5/32 iio:gyro:itg3200: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte array of smaller elements on the stack. This is fixed by using an explicit c structure. As there are no holes in the structure, there is no possiblity of data leakage in this case.

The explicit alignment of ts is not strictly necessary but potentially makes the code slightly less fragile.

Fixes 36e0371e7764 ("iio:itg3200: Use iio_push_to_buffers_with_timestamp()")
---
 drivers/iio/gyro/itg3200_buffer.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/iio/gyro/itg3200_buffer.c +11 -4
index d3fbe9d86467..1c3c1bd53374 100644
@@ -46,13 +46,20 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct itg3200 *st = iio_priv(indio_dev);
-	__be16 buf[ITG3200_SCAN_ELEMENTS + sizeof(s64)/sizeof(u16)];
-
-	int ret = itg3200_read_all_channels(st->i2c, buf);
+	/*
+	 * Ensure correct alignment and padding including for the
+	 * timestamp that may be inserted.
+	 */
+	struct {
+		__be16 buf[ITG3200_SCAN_ELEMENTS];
+		s64 ts __aligned(8);
+	} scan;
+
+	int ret = itg3200_read_all_channels(st->i2c, scan.buf);
 	if (ret < 0)
 		goto error_ret;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp);
 
 	iio_trigger_notify_done(indio_dev->trig);
 
Signature · 1 line
2.26.2
author maintainer
#9 lore raw

PATCH v2 6/32 iio:proximity:mb1232: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte s16 array 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 ensured by use of an explicit c structure. This data is allocated with kzalloc so no data can leak appart from previous readings.

In this case the forced alignment of the ts is necessary to ensure correct padding on x86_32 where the s64 would only be 4 byte aligned.

Fixes 16b05261537e ("mb1232.c: add distance iio sensor with i2c")
Cc Andreas Klinger <[email protected]>
---
 drivers/iio/proximity/mb1232.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/iio/proximity/mb1232.c +9 -8
index 654564c45248..ad4b1fb2607a 100644
@@ -40,6 +40,11 @@ struct mb1232_data {
 	 */
 	struct completion	ranging;
 	int			irqnr;
+	/* Ensure correct alignment of data to push to IIO buffer */
+	struct {
+		s16 distance;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static irqreturn_t mb1232_handle_irq(int irq, void *dev_id)
@@ -113,17 +118,13 @@ static irqreturn_t mb1232_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mb1232_data *data = iio_priv(indio_dev);
-	/*
-	 * triggered buffer
-	 * 16-bit channel + 48-bit padding + 64-bit timestamp
-	 */
-	s16 buffer[8] = { 0 };
 
-	buffer[0] = mb1232_read_distance(data);
-	if (buffer[0] < 0)
+	data->scan.distance = mb1232_read_distance(data);
+	if (data->scan.distance < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+					   pf->timestamp);
 
 err:
 	iio_trigger_notify_done(indio_dev->trig);
Signature · 1 line
2.26.2
author maintainer
#10 lore raw

PATCH v2 7/32 iio:chemical:ccs811: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 appart from previous readings.

The explicit alignment of ts is necessary to ensure consistent padding for x86_32 in which the ts would otherwise be 4 byte aligned.

Fixes 283d26917ad6 ("iio: chemical: ccs811: Add triggered buffer support")
Cc Narcisa Ana Maria Vasile <[email protected]>
---
 drivers/iio/chemical/ccs811.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/iio/chemical/ccs811.c +9 -4
index 2b007e7568b2..60dd87e96f5f 100644
@@ -78,6 +78,11 @@ struct ccs811_data {
 	struct iio_trigger *drdy_trig;
 	struct gpio_desc *wakeup_gpio;
 	bool drdy_trig_on;
+	/* Ensures correct alignment of timestamp if present */
+	struct {
+		s16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static const struct iio_chan_spec ccs811_channels[] = {
@@ -327,17 +332,17 @@ static irqreturn_t ccs811_trigger_handler(int irq, void *p)
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ccs811_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
-	s16 buf[8]; /* s16 eCO2 + s16 TVOC + padding + 8 byte timestamp */
 	int ret;
 
-	ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA, 4,
-					    (u8 *)&buf);
+	ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA,
+					    sizeof(data->scan.channels),
+					    (u8 *)data->scan.channels);
 	if (ret != 4) {
 		dev_err(&client->dev, "cannot read sensor data\n");
 		goto err;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
Signature · 1 line
2.26.2
author maintainer
#11 lore raw

PATCH v2 8/32 iio:light:si1145: Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 24 byte 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 array in the iio_priv() data with alignment explicitly requested. This data is allocated with kzalloc so no data can leak appart from previous readings.

Fixes ac45e57f1590 ("iio: light: Add driver for Silabs si1132, si1141/2/3 and si1145/6/7 ambient light, uv index and proximity sensors")
Cc Peter Meerwald-Stadler <[email protected]>
---
 drivers/iio/light/si1145.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/iio/light/si1145.c +4 -3
index e1f989dd3a3d..16958160cf63 100644
@@ -179,6 +179,8 @@ struct si1145_data {
 	bool autonomous;
 	struct iio_trigger *trig;
 	int meas_rate;
+	/* Ensure timestamp will be naturally aligned if present */
+	u8 buffer[24] __aligned(8);
 };
 
 /**
@@ -445,7 +447,6 @@ static irqreturn_t si1145_trigger_handler(int irq, void *private)
 	 *   6*2 bytes channels data + 4 bytes alignment +
 	 *   8 bytes timestamp
 	 */
-	u8 buffer[24];
 	int i, j = 0;
 	int ret;
 	u8 irq_status = 0;
@@ -478,7 +479,7 @@ static irqreturn_t si1145_trigger_handler(int irq, void *private)
 
 		ret = i2c_smbus_read_i2c_block_data_or_emulated(
 				data->client, indio_dev->channels[i].address,
-				sizeof(u16) * run, &buffer[j]);
+				sizeof(u16) * run, &data->buffer[j]);
 		if (ret < 0)
 			goto done;
 		j += run * sizeof(u16);
@@ -493,7 +494,7 @@ static irqreturn_t si1145_trigger_handler(int irq, void *private)
 			goto done;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 		iio_get_time_ns(indio_dev));
 
 done:
Signature · 1 line
2.26.2
author maintainer
#12 lore raw

PATCH v2 9/32 iio:light:max44000 Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 16 byte 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().
This data is allocated with kzalloc so no data can leak appart from previous readings.

It is necessary to force the alignment of ts to avoid the padding on x86_32 being different from 64 bit platorms (it alows for 4 bytes aligned 8 byte types.

Fixes 06ad7ea10e2b ("max44000: Initial triggered buffer support")
---
 drivers/iio/light/max44000.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/iio/light/max44000.c +8 -4
index aa8ed1e3e89a..b8e721bced5b 100644
@@ -75,6 +75,11 @@
 struct max44000_data {
 	struct mutex lock;
 	struct regmap *regmap;
+	/* Ensure naturally aligned timestamp */
+	struct {
+		u16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */
@@ -488,7 +493,6 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct max44000_data *data = iio_priv(indio_dev);
-	u16 buf[8]; /* 2x u16 + padding + 8 bytes timestamp */
 	int index = 0;
 	unsigned int regval;
 	int ret;
@@ -498,17 +502,17 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p)
 		ret = max44000_read_alsval(data);
 		if (ret < 0)
 			goto out_unlock;
-		buf[index++] = ret;
+		data->scan.channels[index++] = ret;
 	}
 	if (test_bit(MAX44000_SCAN_INDEX_PRX, indio_dev->active_scan_mask)) {
 		ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
 		if (ret < 0)
 			goto out_unlock;
-		buf[index] = regval;
+		data->scan.channels[index] = regval;
 	}
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 	iio_trigger_notify_done(indio_dev->trig);
 	return IRQ_HANDLED;
Signature · 1 line
2.26.2
author maintainer
#13 lore raw

PATCH v2 10/32 iio:light:rpr0521 Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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().
This data is allocated with kzalloc so no data can leak appart from previous readings and in this case the status byte from the device.

The forced alignment of ts is not necessary in this case but it potentially makes the code less fragile.

Fixes e12ffd241c00 ("iio: light: rpr0521 triggered buffer")
Cc Mikko Koivunen <[email protected]>
---
 drivers/iio/light/rpr0521.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
drivers/iio/light/rpr0521.c +13 -4
index c20fbc730d65..66f22ea3d68a 100644
@@ -194,6 +194,17 @@ struct rpr0521_data {
 	bool pxs_need_dis;
 
 	struct regmap *regmap;
+
+	/*
+	 * Ensure correct naturally aligned timestamp.
+	 * Note that the read will put garbage data into
+	 * the padding but this should not be a problem
+	 */
+	struct {
+		__le16 channels[3];
+		u8 garbage;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
@@ -449,8 +460,6 @@ static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p)
 	struct rpr0521_data *data = iio_priv(indio_dev);
 	int err;
 
-	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
-
 	/* Use irq timestamp when reasonable. */
 	if (iio_trigger_using_own(indio_dev) && data->irq_timestamp) {
 		pf->timestamp = data->irq_timestamp;
@@ -461,11 +470,11 @@ static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p)
 		pf->timestamp = iio_get_time_ns(indio_dev);
 
 	err = regmap_bulk_read(data->regmap, RPR0521_REG_PXS_DATA,
-		&buffer,
+		data->scan.channels,
 		(3 * 2) + 1);	/* 3 * 16-bit + (discarded) int clear reg. */
 	if (!err)
 		iio_push_to_buffers_with_timestamp(indio_dev,
-						   buffer, pf->timestamp);
+						   &data->scan, pf->timestamp);
 	else
 		dev_err(&data->client->dev,
 			"Trigger consumer can't read from sensor.\n");
Signature · 1 line
2.26.2
author maintainer
#14 lore raw

PATCH v2 11/32 iio:light:st_uvis25 Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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()

This data is allocated with kzalloc so no data can leak apart from previous readings.

Fixes 3025c8688c1e ("iio: light: add support for UVIS25 sensor")
---
 drivers/iio/light/st_uvis25.h      | 5 +++++
 drivers/iio/light/st_uvis25_core.c | 6 +++---
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/iio/light/st_uvis25.h +5 -0
index 78bc56aad129..283086887caf 100644
@@ -27,6 +27,11 @@ struct st_uvis25_hw {
 	struct iio_trigger *trig;
 	bool enabled;
 	int irq;
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u8 chan;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 extern const struct dev_pm_ops st_uvis25_pm_ops;
drivers/iio/light/st_uvis25_core.c +3 -3
index 4d001d50e775..818b8faea73c 100644
@@ -234,17 +234,17 @@ static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
 
 static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
 {
-	u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
 	struct iio_poll_func *pf = p;
 	struct iio_dev *iio_dev = pf->indio_dev;
 	struct st_uvis25_hw *hw = iio_priv(iio_dev);
 	int err;
 
-	err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
+	err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR,
+			  (unsigned int *)&hw->scan.chan);
 	if (err < 0)
 		goto out;
 
-	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 					   iio_get_time_ns(iio_dev));
 
 out:
Signature · 1 line
2.26.2
author maintainer Applied
#15 lore raw

Re: [PATCH 11/32] iio:light:st_uvis25 Fix timestamp alignment and prevent data leak.

Quoted 10 lines · On Sun, 7 Jun 2020 16:53:47 +0100 Jonathan Cameron <[email protected]> wrote:

From: Jonathan Cameron <[email protected]>

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()

Quoted 7 lines

This data is allocated with kzalloc so no data can leak apart from previous readings.

Fixes 3025c8688c1e ("iio: light: add support for UVIS25 sensor")

Applied to the fixes-togreg branch of iio.git and marked for stable. I'm going to pick up all the ones in this series that I have had an Ack for.

Thanks,

Jonathan

Quoted 46 lines
---
 drivers/iio/light/st_uvis25.h      | 5 +++++
 drivers/iio/light/st_uvis25_core.c | 6 +++---
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/iio/light/st_uvis25.h +5 -0
index 78bc56aad129..283086887caf 100644
@@ -27,6 +27,11 @@ struct st_uvis25_hw {
 	struct iio_trigger *trig;
 	bool enabled;
 	int irq;
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u8 chan;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 extern const struct dev_pm_ops st_uvis25_pm_ops;
drivers/iio/light/st_uvis25_core.c +3 -3
index 4d001d50e775..818b8faea73c 100644
@@ -234,17 +234,17 @@ static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
 
 static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
 {
-	u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
 	struct iio_poll_func *pf = p;
 	struct iio_dev *iio_dev = pf->indio_dev;
 	struct st_uvis25_hw *hw = iio_priv(iio_dev);
 	int err;
 
-	err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
+	err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR,
+			  (unsigned int *)&hw->scan.chan);
 	if (err < 0)
 		goto out;
 
-	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 					   iio_get_time_ns(iio_dev));
 
 out:
#16 lore raw

Re: [PATCH 11/32] iio:light:st_uvis25 Fix timestamp alignment and prevent data leak.

In reply to Jonathan Cameron

On Sun, Jun 7, 2020 at 6:57 PM Jonathan Cameron <[email protected]> wrote:

...

Quoted 6 lines
drivers/iio/light/st_uvis25.h +5 -0
+       /* Ensure timestamp is naturally aligned */
+       struct {
+               u8 chan;
+               s64 ts __aligned(8);
+       } scan;
 };

...

drivers/iio/light/st_uvis25_core.c static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = { · line 243

Quoted 3 lines
drivers/iio/light/st_uvis25_core.c +2 -1
-       err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
+       err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR,
+                         (unsigned int *)&hw->scan.chan);

Despite knowing that this is okay, from a language perspective this casting is not good. Potential mine for all kinds of static analyzers.

I think it should use a temporary unsigned int (or what regmap API wants) variable.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#17 lore raw

Re: [PATCH 11/32] iio:light:st_uvis25 Fix timestamp alignment and prevent data leak.

Quoted 17 lines · On Sun, 5 Jul 2020 15:05:49 +0300 Andy Shevchenko <[email protected]>…

On Sun, Jun 7, 2020 at 6:57 PM Jonathan Cameron <[email protected]> wrote:

...

Quoted 6 lines
drivers/iio/light/st_uvis25.h +5 -0
+       /* Ensure timestamp is naturally aligned */
+       struct {
+               u8 chan;
+               s64 ts __aligned(8);
+       } scan;
 };  

...

drivers/iio/light/st_uvis25_core.c static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = { · line 243

Quoted 3 lines
drivers/iio/light/st_uvis25_core.c +2 -1
-       err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
+       err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR,
+                         (unsigned int *)&hw->scan.chan);  
Quoted 6 lines

Despite knowing that this is okay, from a language perspective this casting is not good. Potential mine for all kinds of static analyzers.

I think it should use a temporary unsigned int (or what regmap API wants) variable.

Good point. Dropped for now. Will revisit.

Thanks,

Jonathan

author maintainer
#18 lore raw

PATCH v2 12/32 iio:light:ltr501 Fix timestamp alignment issue.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. Here we use a structure on the stack. The driver already did an explicit memset so no data leak was possible.

Forced alignment of ts is not strictly necessary but probably makes the code slightly less fragile.

Note there has been some rework in this driver of the years, so no way this will apply cleanly all the way back.

Fixes 2690be905123 ("iio: Add Lite-On ltr501 ambient light / proximity sensor driver")
---
 drivers/iio/light/ltr501.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/iio/light/ltr501.c +9 -6
index 4bac0646398d..b4323d2db0b1 100644
@@ -1243,13 +1243,16 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ltr501_data *data = iio_priv(indio_dev);
-	u16 buf[8];
+	struct {
+		u16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 	__le16 als_buf[2];
 	u8 mask = 0;
 	int j = 0;
 	int ret, psdata;
 
-	memset(buf, 0, sizeof(buf));
+	memset(&scan, 0, sizeof(scan));
 
 	/* figure out which data needs to be ready */
 	if (test_bit(0, indio_dev->active_scan_mask) ||
@@ -1268,9 +1271,9 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
 		if (ret < 0)
 			return ret;
 		if (test_bit(0, indio_dev->active_scan_mask))
-			buf[j++] = le16_to_cpu(als_buf[1]);
+			scan.channels[j++] = le16_to_cpu(als_buf[1]);
 		if (test_bit(1, indio_dev->active_scan_mask))
-			buf[j++] = le16_to_cpu(als_buf[0]);
+			scan.channels[j++] = le16_to_cpu(als_buf[0]);
 	}
 
 	if (mask & LTR501_STATUS_PS_RDY) {
@@ -1278,10 +1281,10 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
 				       &psdata, 2);
 		if (ret < 0)
 			goto done;
-		buf[j++] = psdata & LTR501_PS_DATA_MASK;
+		scan.channels[j++] = psdata & LTR501_PS_DATA_MASK;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 done:
Signature · 1 line
2.26.2
author maintainer
#19 lore raw

PATCH v2 13/32 iio:magnetometer:ak8974: Fix alignment and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

This data is allocated with kzalloc so no data can leak appart from previous readings.

Fixes 7c94a8b2ee8cf ("iio: magn: add a driver for AK8974")
---
 drivers/iio/magnetometer/ak8974.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/magnetometer/ak8974.c +7 -3
index c2260c84f7f1..ea09b549ec4e 100644
@@ -192,6 +192,11 @@ struct ak8974 {
 	bool drdy_irq;
 	struct completion drdy_complete;
 	bool drdy_active_low;
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static const char ak8974_reg_avdd[] = "avdd";
@@ -657,7 +662,6 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev)
 {
 	struct ak8974 *ak8974 = iio_priv(indio_dev);
 	int ret;
-	__le16 hw_values[8]; /* Three axes + 64bit padding */
 
 	pm_runtime_get_sync(&ak8974->i2c->dev);
 	mutex_lock(&ak8974->lock);
@@ -667,13 +671,13 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev)
 		dev_err(&ak8974->i2c->dev, "error triggering measure\n");
 		goto out_unlock;
 	}
-	ret = ak8974_getresult(ak8974, hw_values);
+	ret = ak8974_getresult(ak8974, ak8974->scan.channels);
 	if (ret) {
 		dev_err(&ak8974->i2c->dev, "error getting measures\n");
 		goto out_unlock;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, hw_values,
+	iio_push_to_buffers_with_timestamp(indio_dev, &ak8974->scan,
 					   iio_get_time_ns(indio_dev));
 
  out_unlock:
Signature · 1 line
2.26.2
author maintainer Applied
#20 lore raw

Re: [PATCH 13/32] iio:magnetometer:ak8974: Fix alignment and data leak issues

Quoted 10 lines · On Sun, 7 Jun 2020 16:53:49 +0100 Jonathan Cameron <[email protected]> wrote:

From: Jonathan Cameron <[email protected]>

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.

Quoted 7 lines

This data is allocated with kzalloc so no data can leak appart from previous readings.

Fixes 7c94a8b2ee8cf ("iio: magn: add a driver for AK8974")

Applied to the fixes-togreg branch of iio.git. I'm picking up all the ones in the series which I have had positive feedback on.

Thanks,

Jonathan

Quoted 44 lines
---
 drivers/iio/magnetometer/ak8974.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/magnetometer/ak8974.c +7 -3
index c2260c84f7f1..ea09b549ec4e 100644
@@ -192,6 +192,11 @@ struct ak8974 {
 	bool drdy_irq;
 	struct completion drdy_complete;
 	bool drdy_active_low;
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static const char ak8974_reg_avdd[] = "avdd";
@@ -657,7 +662,6 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev)
 {
 	struct ak8974 *ak8974 = iio_priv(indio_dev);
 	int ret;
-	__le16 hw_values[8]; /* Three axes + 64bit padding */
 
 	pm_runtime_get_sync(&ak8974->i2c->dev);
 	mutex_lock(&ak8974->lock);
@@ -667,13 +671,13 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev)
 		dev_err(&ak8974->i2c->dev, "error triggering measure\n");
 		goto out_unlock;
 	}
-	ret = ak8974_getresult(ak8974, hw_values);
+	ret = ak8974_getresult(ak8974, ak8974->scan.channels);
 	if (ret) {
 		dev_err(&ak8974->i2c->dev, "error getting measures\n");
 		goto out_unlock;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, hw_values,
+	iio_push_to_buffers_with_timestamp(indio_dev, &ak8974->scan,
 					   iio_get_time_ns(indio_dev));
 
  out_unlock:
author maintainer
#21 lore raw

PATCH v2 14/32 iio:magnetometer:ak8975 Fix alignment and data leak issues.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

This data is allocated with kzalloc so no data can leak apart from previous readings.

The explicit alignment of ts is not necessary in this case as by coincidence the padding will end up the same, however I consider it to make the code less fragile and have included it.

Fixes bc11ca4a0b84 ("iio:magnetometer:ak8975: triggered buffer support")
Cc Gregor Boirie <[email protected]>
Cc Andy Shevchenko <[email protected]>
Cc Linus Walleij <[email protected]>
---
 drivers/iio/magnetometer/ak8975.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)
drivers/iio/magnetometer/ak8975.c +14 -6
index 03d71f796177..14d66fd11aa3 100644
@@ -366,6 +366,12 @@ struct ak8975_data {
 	struct iio_mount_matrix orientation;
 	struct regulator	*vdd;
 	struct regulator	*vid;
+
+	/* Ensure natural alignment of timestamp */
+	struct {
+		s16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* Enable attached power regulator if any. */
@@ -793,7 +799,6 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
 	const struct i2c_client *client = data->client;
 	const struct ak_def *def = data->def;
 	int ret;
-	s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */
 	__le16 fval[3];
 
 	mutex_lock(&data->lock);
@@ -816,11 +821,14 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
 	mutex_unlock(&data->lock);
 
 	/* Clamp to valid range. */
-	buff[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
-	buff[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
-	buff[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
-
-	iio_push_to_buffers_with_timestamp(indio_dev, buff,
+	data->scan.channels[0] =
+		clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
+	data->scan.channels[1] =
+		clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
+	data->scan.channels[2] =
+		clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
+
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 	return;
 
Signature · 1 line
2.26.2
author maintainer
#22 lore raw

PATCH v2 15/32 iio:magnetometer:mag3110 Fix alignment and data leak issues.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. This data is allocated with kzalloc so no data can leak apart from previous readings.

The explicit alignment of ts is not necessary in this case but does make the code slightly less fragile so I have included it.

Fixes 39631b5f9584 ("iio: Add Freescale mag3110 magnetometer driver")
---
 drivers/iio/magnetometer/mag3110.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/iio/magnetometer/mag3110.c +9 -4
index 4d305a21c379..e96113ca39bd 100644
@@ -56,6 +56,12 @@ struct mag3110_data {
 	int sleep_val;
 	struct regulator *vdd_reg;
 	struct regulator *vddio_reg;
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__be16 channels[3];
+		u8 temp;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static int mag3110_request(struct mag3110_data *data)
@@ -387,10 +393,9 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mag3110_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 3 16-bit channels + 1 byte temp + padding + ts */
 	int ret;
 
-	ret = mag3110_read(data, (__be16 *) buffer);
+	ret = mag3110_read(data, data->scan.channels);
 	if (ret < 0)
 		goto done;
 
@@ -399,10 +404,10 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
 			MAG3110_DIE_TEMP);
 		if (ret < 0)
 			goto done;
-		buffer[6] = ret;
+		data->scan.temp = ret;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 		iio_get_time_ns(indio_dev));
 
 done:
Signature · 1 line
2.26.2
author maintainer
#23 lore raw

PATCH v2 16/32 iio:humidity:hdc100x Fix alignment and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. This data is allocated with kzalloc so no data can leak apart from previous readings.

Fixes 16bf793f86b2 ("iio: humidity: hdc100x: add triggered buffer support for HDC100X")
Cc Alison Schofield <[email protected]>
---
 drivers/iio/humidity/hdc100x.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/humidity/hdc100x.c +7 -3
index 3331141734c8..e64af35f5f6f 100644
@@ -38,6 +38,11 @@ struct hdc100x_data {
 
 	/* integration time of the sensor */
 	int adc_int_us[2];
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__be16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* integration time in us */
@@ -322,7 +327,6 @@ static irqreturn_t hdc100x_trigger_handler(int irq, void *p)
 	struct i2c_client *client = data->client;
 	int delay = data->adc_int_us[0] + data->adc_int_us[1];
 	int ret;
-	s16 buf[8];  /* 2x s16 + padding + 8 byte timestamp */
 
 	/* dual read starts at temp register */
 	mutex_lock(&data->lock);
@@ -333,13 +337,13 @@ static irqreturn_t hdc100x_trigger_handler(int irq, void *p)
 	}
 	usleep_range(delay, delay + 1000);
 
-	ret = i2c_master_recv(client, (u8 *)buf, 4);
+	ret = i2c_master_recv(client, (u8 *)data->scan.channels, 4);
 	if (ret < 0) {
 		dev_err(&client->dev, "cannot read sensor data\n");
 		goto err;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 err:
 	mutex_unlock(&data->lock);
Signature · 1 line
2.26.2
author maintainer Applied
#24 lore raw

Re: [PATCH 16/32] iio:humidity:hdc100x Fix alignment and data leak issues

Quoted 12 lines · On Sun, 7 Jun 2020 16:53:52 +0100 Jonathan Cameron <[email protected]> wrote:

From: Jonathan Cameron <[email protected]>

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. This data is allocated with kzalloc so no data can leak apart from previous readings.

Quoted 5 lines
Fixes 16bf793f86b2 ("iio: humidity: hdc100x: add triggered buffer support for HDC100X")
Cc Alison Schofield <[email protected]>

Applied to the fixes-togreg branch of iio.git.
I'm scooping up all the ones in this series that have have acks etc as then I can work on getting eyes on the remainder.

Thanks,

Jonathan

Quoted 44 lines
---
 drivers/iio/humidity/hdc100x.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/humidity/hdc100x.c +7 -3
index 3331141734c8..e64af35f5f6f 100644
@@ -38,6 +38,11 @@ struct hdc100x_data {
 
 	/* integration time of the sensor */
 	int adc_int_us[2];
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__be16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* integration time in us */
@@ -322,7 +327,6 @@ static irqreturn_t hdc100x_trigger_handler(int irq, void *p)
 	struct i2c_client *client = data->client;
 	int delay = data->adc_int_us[0] + data->adc_int_us[1];
 	int ret;
-	s16 buf[8];  /* 2x s16 + padding + 8 byte timestamp */
 
 	/* dual read starts at temp register */
 	mutex_lock(&data->lock);
@@ -333,13 +337,13 @@ static irqreturn_t hdc100x_trigger_handler(int irq, void *p)
 	}
 	usleep_range(delay, delay + 1000);
 
-	ret = i2c_master_recv(client, (u8 *)buf, 4);
+	ret = i2c_master_recv(client, (u8 *)data->scan.channels, 4);
 	if (ret < 0) {
 		dev_err(&client->dev, "cannot read sensor data\n");
 		goto err;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 err:
 	mutex_unlock(&data->lock);
author maintainer
#25 lore raw

PATCH v2 17/32 iio:humidity:hts221 Fix alignment and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. This data is allocated with kzalloc so no data can leak apart from previous readings.

Explicit alignment of ts needed to ensure consistent padding on all architectures (particularly x86_32 with it's 4 byte alignment of s64)

Fixes e4a70e3e7d84 ("iio: humidity: add support to hts221 rh/temp combo device")
---
 drivers/iio/humidity/hts221.h        | 7 +++++--
 drivers/iio/humidity/hts221_buffer.c | 9 +++++----
 2 files changed, 10 insertions(+), 6 deletions(-)
drivers/iio/humidity/hts221.h +5 -2
index 7c650df77556..721359e226cb 100644
@@ -14,8 +14,6 @@
 
 #include <linux/iio/iio.h>
 
-#define HTS221_DATA_SIZE	2
-
 enum hts221_sensor_type {
 	HTS221_SENSOR_H,
 	HTS221_SENSOR_T,
@@ -39,6 +37,11 @@ struct hts221_hw {
 
 	bool enabled;
 	u8 odr;
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__le16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 extern const struct dev_pm_ops hts221_pm_ops;
drivers/iio/humidity/hts221_buffer.c +5 -4
index 21c6c160462d..59ede9860185 100644
@@ -160,7 +160,6 @@ static const struct iio_buffer_setup_ops hts221_buffer_ops = {
 
 static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 {
-	u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)];
 	struct iio_poll_func *pf = p;
 	struct iio_dev *iio_dev = pf->indio_dev;
 	struct hts221_hw *hw = iio_priv(iio_dev);
@@ -170,18 +169,20 @@ static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 	/* humidity data */
 	ch = &iio_dev->channels[HTS221_SENSOR_H];
 	err = regmap_bulk_read(hw->regmap, ch->address,
-			       buffer, HTS221_DATA_SIZE);
+			       &hw->scan.channels[0],
+			       sizeof(hw->scan.channels[0]));
 	if (err < 0)
 		goto out;
 
 	/* temperature data */
 	ch = &iio_dev->channels[HTS221_SENSOR_T];
 	err = regmap_bulk_read(hw->regmap, ch->address,
-			       buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
+			       &hw->scan.channels[1],
+			       sizeof(hw->scan.channels[1]));
 	if (err < 0)
 		goto out;
 
-	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 					   iio_get_time_ns(iio_dev));
 
 out:
Signature · 1 line
2.26.2
author maintainer Applied
#26 lore raw

Re: [PATCH 17/32] iio:humidity:hts221 Fix alignment and data leak issues

Quoted 12 lines · On Sun, 7 Jun 2020 16:53:53 +0100 Jonathan Cameron <[email protected]> wrote:

From: Jonathan Cameron <[email protected]>

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. This data is allocated with kzalloc so no data can leak apart from previous readings.

Quoted 8 lines

Explicit alignment of ts needed to ensure consistent padding on all architectures (particularly x86_32 with it's 4 byte alignment of s64)

Fixes e4a70e3e7d84 ("iio: humidity: add support to hts221 rh/temp combo device")

Applied to the fixes-togreg branch of iio.git and marked for stable. I'm scooping up all the ones in this series for which I have an ack so that we can focus on getting remainder reviewed.

Thanks,

Jonathan

Quoted 66 lines
---
 drivers/iio/humidity/hts221.h        | 7 +++++--
 drivers/iio/humidity/hts221_buffer.c | 9 +++++----
 2 files changed, 10 insertions(+), 6 deletions(-)
drivers/iio/humidity/hts221.h +5 -2
index 7c650df77556..721359e226cb 100644
@@ -14,8 +14,6 @@
 
 #include <linux/iio/iio.h>
 
-#define HTS221_DATA_SIZE	2
-
 enum hts221_sensor_type {
 	HTS221_SENSOR_H,
 	HTS221_SENSOR_T,
@@ -39,6 +37,11 @@ struct hts221_hw {
 
 	bool enabled;
 	u8 odr;
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__le16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 extern const struct dev_pm_ops hts221_pm_ops;
drivers/iio/humidity/hts221_buffer.c +5 -4
index 21c6c160462d..59ede9860185 100644
@@ -160,7 +160,6 @@ static const struct iio_buffer_setup_ops hts221_buffer_ops = {
 
 static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 {
-	u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)];
 	struct iio_poll_func *pf = p;
 	struct iio_dev *iio_dev = pf->indio_dev;
 	struct hts221_hw *hw = iio_priv(iio_dev);
@@ -170,18 +169,20 @@ static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 	/* humidity data */
 	ch = &iio_dev->channels[HTS221_SENSOR_H];
 	err = regmap_bulk_read(hw->regmap, ch->address,
-			       buffer, HTS221_DATA_SIZE);
+			       &hw->scan.channels[0],
+			       sizeof(hw->scan.channels[0]));
 	if (err < 0)
 		goto out;
 
 	/* temperature data */
 	ch = &iio_dev->channels[HTS221_SENSOR_T];
 	err = regmap_bulk_read(hw->regmap, ch->address,
-			       buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
+			       &hw->scan.channels[1],
+			       sizeof(hw->scan.channels[1]));
 	if (err < 0)
 		goto out;
 
-	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 					   iio_get_time_ns(iio_dev));
 
 out:
author maintainer
#27 lore raw

PATCH v2 18/32 iio:imu:bmi160 Fix alignment and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 array in the iio_priv() data with alignment explicitly requested. This data is allocated with kzalloc so no data can leak apart from previous readings.

Fixes 77c4ad2d6a9b ("iio: imu: Add initial support for Bosch BMI160")
Cc Daniel Baluta <[email protected]>
---
 drivers/iio/imu/bmi160/bmi160.h      | 2 ++
 drivers/iio/imu/bmi160/bmi160_core.c | 5 ++---
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/iio/imu/bmi160/bmi160.h +2 -0
index a82e040bd109..d29f1b5d1658 100644
@@ -10,6 +10,8 @@ struct bmi160_data {
 	struct iio_trigger *trig;
 	struct regulator_bulk_data supplies[2];
 	struct iio_mount_matrix orientation;
+	/* Ensure natural alignment for timestamp if present */
+	__le16 buf[16] __aligned(8);
 };
 
 extern const struct regmap_config bmi160_regmap_config;
drivers/iio/imu/bmi160/bmi160_core.c +2 -3
index 222ebb26f013..86cfd75ea125 100644
@@ -427,7 +427,6 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct bmi160_data *data = iio_priv(indio_dev);
-	__le16 buf[16];
 	/* 3 sens x 3 axis x __le16 + 3 x __le16 pad + 4 x __le16 tstamp */
 	int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
 	__le16 sample;
@@ -438,10 +437,10 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
 				       &sample, sizeof(sample));
 		if (ret)
 			goto done;
-		buf[j++] = sample;
+		data->buf[j++] = sample;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buf, pf->timestamp);
 done:
 	iio_trigger_notify_done(indio_dev->trig);
 	return IRQ_HANDLED;
Signature · 1 line
2.26.2
#28 lore raw

Re: [PATCH 18/32] iio:imu:bmi160 Fix alignment and data leak issues

Quoted 12 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 array in the iio_priv() data with alignment explicitly requested. This data is allocated with kzalloc so no data can leak apart from previous readings.

drivers/iio/imu/bmi160/bmi160.h struct bmi160_data { · line 14

Quoted 2 lines
drivers/iio/imu/bmi160/bmi160.h +2 -0
+	/* Ensure natural alignment for timestamp if present */
+	__le16 buf[16] __aligned(8);

Perhaps struct in all such cases, like

 struct scan {
	 __le16 buf[3 * 3]; // 3 axis per 3 sensors
	 s64 ts; __aligned(8);

};

?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#29 lore raw

Re: [PATCH 18/32] iio:imu:bmi160 Fix alignment and data leak issues

Quoted 18 lines · On Mon, 8 Jun 2020 16:17:12 +0300 Andy Shevchenko…
Quoted 12 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 array in the iio_priv() data with alignment explicitly requested. This data is allocated with kzalloc so no data can leak apart from previous readings.

drivers/iio/imu/bmi160/bmi160.h struct bmi160_data { · line 14

Quoted 2 lines
drivers/iio/imu/bmi160/bmi160.h +2 -0
+	/* Ensure natural alignment for timestamp if present */
+	__le16 buf[16] __aligned(8);  

Perhaps struct in all such cases, like

Quoted 7 lines
 struct scan {
	 __le16 buf[3 * 3]; // 3 axis per 3 sensors
	 s64 ts; __aligned(8);

};

?

I did that for all the cases where the timestamp could only appear in one location, which are those with 8 bytes or less of channels + any which don't have flexible channel configs.

Unfortunately that's not always the case in this driver. It depends on how
many channels are turned on. As they are 2 bytes each, if you have
only 1-4 channels enabled, then the timestamp will start at 8 bytes in. If you have 5-8 channels enabled it'll be 8 bytes in, if you have 9 channels it will be 24 bytes in.

I thought about just ignoring that and pretending the timestamp was always in the same place but my thought was that we'd be implying something false and weird bugs lie down that sort of route.

We could in theory do

union {
	struct {
		__le16 buf[3 * 3];
		s64 ts __aligned(8) 
	};
	struct {
		__le16 buf[4];
		s64 ts __aligned(8);
	} short1;
	struct {
		__le16 buf[8];
		s64 ts __aligned(8);
	} short2;	
} scan;

But I guess you can see why I didn't go that route.

Jonathan

author maintainer
#30 lore raw

PATCH v2 19/32 iio:imu:st_lsm6dsx Fix alignment and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 set of suitable structures in the iio_priv() data.

This data is allocated with kzalloc so no data can leak apart from previous readings.

For the tagged path the data is aligned by using __aligned(8) for the buffer on the stack.

There has been a lot of churn in this driver, so likely backports may be needed for stable.

Fixes 290a6ce11d93 ("iio: imu: add support to lsm6dsx driver")
Cc Lorenzo Bianconi <[email protected]>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  5 +++
 .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c    | 36 ++++++++++---------
 2 files changed, 25 insertions(+), 16 deletions(-)
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +5 -0
index b56df409ed0f..5f821ef467da 100644
@@ -411,6 +411,11 @@ struct st_lsm6dsx_hw {
 	const struct st_lsm6dsx_settings *settings;
 
 	struct iio_mount_matrix orientation;
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} gyro_scan, acc_scan, ext_scan;
 };
 
 static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +20 -16
index afd00daeefb2..bebbc2bb37f7 100644
@@ -341,9 +341,6 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 	int err, sip, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset;
 	u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
 	u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
-	u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
-	u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
-	u8 ext_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
 	bool reset_ts = false;
 	__le16 fifo_status;
 	s64 ts = 0;
@@ -404,19 +401,22 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 
 		while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) {
 			if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
-				memcpy(gyro_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->gyro_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->gyro_scan.channels));
+				offset += sizeof(hw->gyro_scan.channels);
 			}
 			if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
-				memcpy(acc_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->acc_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->acc_scan.channels));
+				offset += sizeof(hw->acc_scan.channels);
 			}
 			if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
-				memcpy(ext_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->ext_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->ext_scan.channels));
+				offset += sizeof(hw->ext_scan.channels);
 			}
 
 			if (ts_sip-- > 0) {
@@ -446,19 +446,22 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 			if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_GYRO],
-					gyro_buff, gyro_sensor->ts_ref + ts);
+					&hw->gyro_scan,
+					gyro_sensor->ts_ref + ts);
 				gyro_sip--;
 			}
 			if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_ACC],
-					acc_buff, acc_sensor->ts_ref + ts);
+					&hw->acc_scan,
+					acc_sensor->ts_ref + ts);
 				acc_sip--;
 			}
 			if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_EXT0],
-					ext_buff, ext_sensor->ts_ref + ts);
+					&hw->ext_scan,
+					ext_sensor->ts_ref + ts);
 				ext_sip--;
 			}
 			sip++;
@@ -543,7 +546,8 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
 {
 	u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
 	u16 fifo_len, fifo_diff_mask;
-	u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag;
+	u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8);
+	u8 tag;
 	bool reset_ts = false;
 	int i, err, read_len;
 	__le16 fifo_status;
Signature · 1 line
2.26.2
maintainer Acked-by on v2 19/32
#31 lore raw

Re: [PATCH 19/32] iio:imu:st_lsm6dsx Fix alignment and data leak issues

Quoted 10 lines

From: Jonathan Cameron <[email protected]>

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 set of suitable structures in the iio_priv() data.

Quoted 8 lines

This data is allocated with kzalloc so no data can leak apart from previous readings.

For the tagged path the data is aligned by using __aligned(8) for the buffer on the stack.

There has been a lot of churn in this driver, so likely backports may be needed for stable.

Hi Jonathan,

I added just some nitpicks inline, but it seems to me the patch is fine. I guess we can address them with a followup patch if you agree, no need to resend this huge series :)

Quoted 15 lines
Fixes 290a6ce11d93 ("iio: imu: add support to lsm6dsx driver")
Cc Lorenzo Bianconi <[email protected]>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  5 +++
 .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c    | 36 ++++++++++---------
 2 files changed, 25 insertions(+), 16 deletions(-)
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +0 -0
index b56df409ed0f..5f821ef467da 100644

drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h struct st_lsm6dsx_hw { · line 419

Quoted 9 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +5 -0
@@ -411,6 +411,11 @@ struct st_lsm6dsx_hw {
 	const struct st_lsm6dsx_settings *settings;
 
 	struct iio_mount_matrix orientation;
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} gyro_scan, acc_scan, ext_scan;
 };

it seems to me doing something like:

struct {
	__le16 channels[3];
	s64 ts __aligned(8);
} scan[3];

would be better if for example we want to add support for more external devices for untagged FIFO devices

Quoted 75 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +0 -0
 static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +18 -15
index afd00daeefb2..bebbc2bb37f7 100644
@@ -341,9 +341,6 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 	int err, sip, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset;
 	u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
 	u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
-	u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
-	u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
-	u8 ext_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
 	bool reset_ts = false;
 	__le16 fifo_status;
 	s64 ts = 0;
@@ -404,19 +401,22 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 
 		while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) {
 			if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
-				memcpy(gyro_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->gyro_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->gyro_scan.channels));
+				offset += sizeof(hw->gyro_scan.channels);
 			}
 			if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
-				memcpy(acc_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->acc_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->acc_scan.channels));
+				offset += sizeof(hw->acc_scan.channels);
 			}
 			if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
-				memcpy(ext_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->ext_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->ext_scan.channels));
+				offset += sizeof(hw->ext_scan.channels);
 			}
 
 			if (ts_sip-- > 0) {
@@ -446,19 +446,22 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 			if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_GYRO],
-					gyro_buff, gyro_sensor->ts_ref + ts);
+					&hw->gyro_scan,
+					gyro_sensor->ts_ref + ts);
 				gyro_sip--;
 			}
 			if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_ACC],
-					acc_buff, acc_sensor->ts_ref + ts);
+					&hw->acc_scan,
+					acc_sensor->ts_ref + ts);
 				acc_sip--;
 			}
 			if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_EXT0],
-					ext_buff, ext_sensor->ts_ref + ts);
+					&hw->ext_scan,
+					ext_sensor->ts_ref + ts);
 				ext_sip--;
 			}
 			sip++;

drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) · line 549

Quoted 5 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +1 -1
@@ -543,7 +546,8 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
 {
 	u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
 	u16 fifo_len, fifo_diff_mask;
-	u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag;
+	u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8);

here we can use hw->scan[0] and drop the array on the stack

Quoted 7 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +1 -0
+	u8 tag;
 	bool reset_ts = false;
 	int i, err, read_len;
 	__le16 fifo_status;
Signature · 1 line
2.26.2
author maintainer
#32 lore raw

Re: [PATCH 19/32] iio:imu:st_lsm6dsx Fix alignment and data leak issues

Quoted 19 lines · On Mon, 8 Jun 2020 00:33:51 +0200 Lorenzo Bianconi <[email protected]> wrote:
Quoted 10 lines

From: Jonathan Cameron <[email protected]>

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 set of suitable structures in the iio_priv() data.

Quoted 8 lines

This data is allocated with kzalloc so no data can leak apart from previous readings.

For the tagged path the data is aligned by using __aligned(8) for the buffer on the stack.

There has been a lot of churn in this driver, so likely backports may be needed for stable.

Quoted 8 lines

Hi Jonathan,

I added just some nitpicks inline, but it seems to me the patch is fine. I guess we can address them with a followup patch if you agree, no need to resend this huge series :)

Hi Lorenzo,

I finally got back to this.

Quoted 27 lines
Quoted 15 lines
Fixes 290a6ce11d93 ("iio: imu: add support to lsm6dsx driver")
Cc Lorenzo Bianconi <[email protected]>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  5 +++
 .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c    | 36 ++++++++++---------
 2 files changed, 25 insertions(+), 16 deletions(-)
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +0 -0
index b56df409ed0f..5f821ef467da 100644

drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h struct st_lsm6dsx_hw { · line 419

Quoted 9 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +5 -0
@@ -411,6 +411,11 @@ struct st_lsm6dsx_hw {
 	const struct st_lsm6dsx_settings *settings;
 
 	struct iio_mount_matrix orientation;
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} gyro_scan, acc_scan, ext_scan;
 };  

it seems to me doing something like:

Quoted 7 lines
struct {
	__le16 channels[3];
	s64 ts __aligned(8);
} scan[3];

would be better if for example we want to add support for more external devices for untagged FIFO devices

Fair enough. I'll do that bit.

Quoted 75 lines
Quoted 75 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +0 -0
 static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +18 -15
index afd00daeefb2..bebbc2bb37f7 100644
@@ -341,9 +341,6 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 	int err, sip, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset;
 	u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
 	u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
-	u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
-	u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
-	u8 ext_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
 	bool reset_ts = false;
 	__le16 fifo_status;
 	s64 ts = 0;
@@ -404,19 +401,22 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 
 		while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) {
 			if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
-				memcpy(gyro_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->gyro_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->gyro_scan.channels));
+				offset += sizeof(hw->gyro_scan.channels);
 			}
 			if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
-				memcpy(acc_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->acc_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->acc_scan.channels));
+				offset += sizeof(hw->acc_scan.channels);
 			}
 			if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
-				memcpy(ext_buff, &hw->buff[offset],
-				       ST_LSM6DSX_SAMPLE_SIZE);
-				offset += ST_LSM6DSX_SAMPLE_SIZE;
+				memcpy(hw->ext_scan.channels,
+				       &hw->buff[offset],
+				       sizeof(hw->ext_scan.channels));
+				offset += sizeof(hw->ext_scan.channels);
 			}
 
 			if (ts_sip-- > 0) {
@@ -446,19 +446,22 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 			if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_GYRO],
-					gyro_buff, gyro_sensor->ts_ref + ts);
+					&hw->gyro_scan,
+					gyro_sensor->ts_ref + ts);
 				gyro_sip--;
 			}
 			if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_ACC],
-					acc_buff, acc_sensor->ts_ref + ts);
+					&hw->acc_scan,
+					acc_sensor->ts_ref + ts);
 				acc_sip--;
 			}
 			if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
 				iio_push_to_buffers_with_timestamp(
 					hw->iio_devs[ST_LSM6DSX_ID_EXT0],
-					ext_buff, ext_sensor->ts_ref + ts);
+					&hw->ext_scan,
+					ext_sensor->ts_ref + ts);
 				ext_sip--;
 			}
 			sip++;
Quoted 8 lines

drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) · line 549

Quoted 6 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +1 -1
@@ -543,7 +546,8 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
 {
 	u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
 	u16 fifo_len, fifo_diff_mask;
-	u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag;
+	u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8);  

here we can use hw->scan[0] and drop the array on the stack

This gets trickier because the scan can have other types of data in it. The timestamp doesn't match with our carefully created structure for scan[].

Hence I'd rather leave this one be, or define another structure to accommodate it.

Jonathan

Quoted 8 lines
Quoted 8 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +1 -0
+	u8 tag;
 	bool reset_ts = false;
 	int i, err, read_len;
 	__le16 fifo_status;
Signature · 1 line
2.26.2
maintainer
#33 lore raw

Re: [PATCH 19/32] iio:imu:st_lsm6dsx Fix alignment and data leak issues

[...]

Quoted 7 lines
Quoted 1 line

here we can use hw->scan[0] and drop the array on the stack

This gets trickier because the scan can have other types of data in it. The timestamp doesn't match with our carefully created structure for scan[].

Hence I'd rather leave this one be, or define another structure to accommodate it.

Hi Jonathan,

ack, I am fine with it.

Regards,
Lorenzo

Quoted 12 lines

Jonathan

Quoted 8 lines
Quoted 8 lines
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +1 -0
+	u8 tag;
 	bool reset_ts = false;
 	int i, err, read_len;
 	__le16 fifo_status;
Signature · 1 line
2.26.2
author maintainer
#34 lore raw

PATCH v2 20/32 iio:imu:inv_mpu6050 Fix dma and ts alignment and data leak issues.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

This case is a bit different to the rest of the series. The driver was doing a regmap_bulk_read into a buffer that wasn't dma safe as it was on the stack with no guarantee of it being in a cacheline
on it's own. Fixing that also dealt with the data leak and
alignment issues that Lars-Peter pointed out.

Also removed some unaligned handling as we are now aligned.

Fixes tag is for the dma safe buffer issue. Potentially we would need to backport timestamp alignment futher but that is a totally different patch.

Fixes fd64df16f40e ("iio: imu: inv_mpu6050: Add SPI support for MPU6000")
Cc Jean-Baptiste Maneyrol <[email protected]>
---
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h  |  8 +++++---
 drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 12 ++++++------
 2 files changed, 11 insertions(+), 9 deletions(-)
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +5 -3
index cd38b3fccc7b..e4df2d51b689 100644
@@ -122,6 +122,9 @@ struct inv_mpu6050_chip_config {
 	u8 user_ctrl;
 };
 
+/* 6 + 6 + 2 + 7 (for MPU9x50) = 21 round up to 24 and plus 8 */
+#define INV_MPU6050_OUTPUT_DATA_SIZE         32
+
 /**
  *  struct inv_mpu6050_hw - Other important hardware information.
  *  @whoami:	Self identification byte from WHO_AM_I register
@@ -165,6 +168,7 @@ struct inv_mpu6050_hw {
  *  @magn_raw_to_gauss:	coefficient to convert mag raw value to Gauss.
  *  @magn_orient:       magnetometer sensor chip orientation if available.
  *  @suspended_sensors:	sensors mask of sensors turned off for suspend
+ *  @data:		dma safe buffer used for bulk reads.
  */
 struct inv_mpu6050_state {
 	struct mutex lock;
@@ -190,6 +194,7 @@ struct inv_mpu6050_state {
 	s32 magn_raw_to_gauss[3];
 	struct iio_mount_matrix magn_orient;
 	unsigned int suspended_sensors;
+	u8 data[INV_MPU6050_OUTPUT_DATA_SIZE] ____cacheline_aligned;
 };
 
 /*register and associated bit definition*/
@@ -334,9 +339,6 @@ struct inv_mpu6050_state {
 #define INV_ICM20608_TEMP_OFFSET	     8170
 #define INV_ICM20608_TEMP_SCALE		     3059976
 
-/* 6 + 6 + 2 + 7 (for MPU9x50) = 21 round up to 24 and plus 8 */
-#define INV_MPU6050_OUTPUT_DATA_SIZE         32
-
 #define INV_MPU6050_REG_INT_PIN_CFG	0x37
 #define INV_MPU6050_ACTIVE_HIGH		0x00
 #define INV_MPU6050_ACTIVE_LOW		0x80
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +6 -6
index 9511e4715e2c..554c16592d47 100644
@@ -13,7 +13,6 @@
 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/math64.h>
-#include <asm/unaligned.h>
 #include "inv_mpu_iio.h"
 
 /**
@@ -121,7 +120,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 	size_t bytes_per_datum;
 	int result;
-	u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
 	u16 fifo_count;
 	s64 timestamp;
 	int int_status;
@@ -160,11 +158,12 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 	 * read fifo_count register to know how many bytes are inside the FIFO
 	 * right now
 	 */
-	result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data,
+	result = regmap_bulk_read(st->map, st->reg->fifo_count_h,
+				  st->data,
 				  INV_MPU6050_FIFO_COUNT_BYTE);
 	if (result)
 		goto end_session;
-	fifo_count = get_unaligned_be16(&data[0]);
+	fifo_count = be16_to_cpup((__be16 *)&st->data[0]);
 
 	/*
 	 * Handle fifo overflow by resetting fifo.
@@ -182,7 +181,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 	inv_mpu6050_update_period(st, pf->timestamp, nb);
 	for (i = 0; i < nb; ++i) {
 		result = regmap_bulk_read(st->map, st->reg->fifo_r_w,
-					  data, bytes_per_datum);
+					  st->data, bytes_per_datum);
 		if (result)
 			goto flush_fifo;
 		/* skip first samples if needed */
@@ -191,7 +190,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 			continue;
 		}
 		timestamp = inv_mpu6050_get_timestamp(st);
-		iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
+		iio_push_to_buffers_with_timestamp(indio_dev, st->data,
+						   timestamp);
 	}
 
 end_session:
Signature · 1 line
2.26.2
Reviewed-by on v2 20/32
#35 lore raw

Re: [PATCH 20/32] iio:imu:inv_mpu6050 Fix dma and ts alignment and data leak issues.

Hi Jonathan,

as stated before, I think this is a good opportunity to fix FIFO data reading by replacing regmap_bulk_read by regmap_noinc_read. Otherwise it could also be done in another patch.

Except that everything is perfect for me.

Thanks,
JB

From: Jonathan Cameron <[email protected]>
Sent: Sunday, June 7, 2020 17:53
To: [email protected] <[email protected]>
Cc: Andy Shevchenko <[email protected]>; Jonathan Cameron <[email protected]>; Lars-Peter Clausen <[email protected]>; Jean-Baptiste Maneyrol <[email protected]>
Subject: [PATCH 20/32] iio:imu:inv_mpu6050 Fix dma and ts alignment and data leak issues.

 CAUTION: This email originated from outside of the organization. Please make sure the sender is who they say they are and do not click links or open attachments unless you recognize the sender and know the content is safe.

From: Jonathan Cameron <[email protected]>

This case is a bit different to the rest of the series.  The driver was doing a regmap_bulk_read into a buffer that wasn't dma safe as it was on the stack with no guarantee of it being in a cacheline on it's own.   Fixing that also dealt with the data leak and alignment issues that Lars-Peter pointed out.

Also removed some unaligned handling as we are now aligned.

Fixes tag is for the dma safe buffer issue. Potentially we would need to backport timestamp alignment futher but that is a totally different patch.

Fixes fd64df16f40e ("iio: imu: inv_mpu6050: Add SPI support for MPU6000")
Cc Jean-Baptiste Maneyrol <[email protected]>

---
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h  |  8 +++++--- drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 12 ++++++------

 2 files changed, 11 insertions(+), 9 deletions(-)
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +0 -0
index cd38b3fccc7b..e4df2d51b689 100644
@@ -122,6 +122,9 @@ struct inv_mpu6050_chip_config {

         u8 user_ctrl;
 };

+/* 6 + 6 + 2 + 7 (for MPU9x50) = 21 round up to 24 and plus 8 */ +#define INV_MPU6050_OUTPUT_DATA_SIZE         32
+
 /**
  *  struct inv_mpu6050_hw - Other important hardware information. *  @whoami:   Self identification byte from WHO_AM_I register @@ -165,6 +168,7 @@ struct inv_mpu6050_hw {
  *  @magn_raw_to_gauss:        coefficient to convert mag raw value to Gauss. *  @magn_orient:       magnetometer sensor chip orientation if available. *  @suspended_sensors:        sensors mask of sensors turned off for suspend
+ *  @data:             dma safe buffer used for bulk reads.
  */
 struct inv_mpu6050_state {
         struct mutex lock;
@@ -190,6 +194,7 @@ struct inv_mpu6050_state {
         s32 magn_raw_to_gauss[3];
         struct iio_mount_matrix magn_orient;
         unsigned int suspended_sensors;
+       u8 data[INV_MPU6050_OUTPUT_DATA_SIZE] ____cacheline_aligned; };

 /*register and associated bit definition*/
@@ -334,9 +339,6 @@ struct inv_mpu6050_state {
 #define INV_ICM20608_TEMP_OFFSET             8170
 #define INV_ICM20608_TEMP_SCALE              3059976

-/* 6 + 6 + 2 + 7 (for MPU9x50) = 21 round up to 24 and plus 8 */ -#define INV_MPU6050_OUTPUT_DATA_SIZE         32
-
 #define INV_MPU6050_REG_INT_PIN_CFG     0x37
 #define INV_MPU6050_ACTIVE_HIGH         0x00
 #define INV_MPU6050_ACTIVE_LOW          0x80

drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +0 -0
index 9511e4715e2c..554c16592d47 100644
@@ -13,7 +13,6 @@

 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/math64.h>
-#include <asm/unaligned.h>
 #include "inv_mpu_iio.h"

 /**
@@ -121,7 +120,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) struct inv_mpu6050_state *st = iio_priv(indio_dev); size_t bytes_per_datum;
         int result;
-       u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
         u16 fifo_count;
         s64 timestamp;
         int int_status;
@@ -160,11 +158,12 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
          * read fifo_count register to know how many bytes are inside the FIFO
          * right now
          */
-       result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data, +       result = regmap_bulk_read(st->map, st->reg->fifo_count_h, +                                 st->data, INV_MPU6050_FIFO_COUNT_BYTE); if (result)
                 goto end_session;
-       fifo_count = get_unaligned_be16(&data[0]);
+       fifo_count = be16_to_cpup((__be16 *)&st->data[0]);

         /*
          * Handle fifo overflow by resetting fifo.
@@ -182,7 +181,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) inv_mpu6050_update_period(st, pf->timestamp, nb);
         for (i = 0; i < nb; ++i) {
                 result = regmap_bulk_read(st->map, st->reg->fifo_r_w, -                                         data, bytes_per_datum); +                                         st->data, bytes_per_datum); if (result)
                         goto flush_fifo;
                 /* skip first samples if needed */
@@ -191,7 +190,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) continue;
                 }
                 timestamp = inv_mpu6050_get_timestamp(st);
-               iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); +               iio_push_to_buffers_with_timestamp(indio_dev, st->data, +                                                  timestamp);
         }

 end_session:

Signature · 1 line
2.26.2
#36 lore raw

Re: [PATCH 20/32] iio:imu:inv_mpu6050 Fix dma and ts alignment and data leak issues.

Quoted 4 lines · Jean-Baptiste Maneyrol

Hi Jonathan,

as stated before, I think this is a good opportunity to fix FIFO data reading by replacing regmap_bulk_read by regmap_noinc_read. Otherwise it could also be done in another patch.

It seems I didn't get this series to my work email, so, sorry for answering here.

Quoted 5 lines

-       result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data, +       result = regmap_bulk_read(st->map, st->reg->fifo_count_h,

+                                 st->data, INV_MPU6050_FIFO_COUNT_BYTE);

Now this can be one line :-)

...

Quoted 3 lines

-               iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); +               iio_push_to_buffers_with_timestamp(indio_dev, st->data, +                                                  timestamp);

And this seems redundant change.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#37 lore raw

PATCH v2 21/32 iio:pressure:ms5611 Fix buffer element alignment

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. Here there is no data leak possibility so use an explicit structure on the stack to ensure alignment and nice readable fashion.

The forced alignment of ts isn't strictly necessary in this driver as the padding will be correct anyway (there isn't any). However it is probably less fragile to have it there and it acts as documentation of the requirement.

Fixes 713bbb4efb9dc ("iio: pressure: ms5611: Add triggered buffer support")
---
 drivers/iio/pressure/ms5611_core.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/iio/pressure/ms5611_core.c +8 -3
index d451bb9dffc8..214b0d25f598 100644
@@ -212,16 +212,21 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ms5611_state *st = iio_priv(indio_dev);
-	s32 buf[4]; /* s32 (pressure) + s32 (temp) + 2 * s32 (timestamp) */
+	/* Ensure buffer elements are naturally aligned */
+	struct {
+		s32 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 	int ret;
 
 	mutex_lock(&st->lock);
-	ret = ms5611_read_temp_and_pressure(indio_dev, &buf[1], &buf[0]);
+	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
+					    &scan.channels[0]);
 	mutex_unlock(&st->lock);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
Signature · 1 line
2.26.2
Acked-by on v2 21/32
#38 lore raw

Re: [PATCH 21/32] iio:pressure:ms5611 Fix buffer element alignment

Quoted 9 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. Here there is no data leak possibility so use an explicit structure on the stack to ensure alignment and nice readable fashion.

Quoted 5 lines

The forced alignment of ts isn't strictly necessary in this driver as the padding will be correct anyway (there isn't any). However it is probably less fragile to have it there and it acts as documentation of the requirement.

Looks good.

Quoted 39 lines
Fixes 713bbb4efb9dc ("iio: pressure: ms5611: Add triggered buffer support")
---
 drivers/iio/pressure/ms5611_core.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/iio/pressure/ms5611_core.c +8 -4
index d451bb9dffc8..214b0d25f598 100644
@@ -212,16 +212,21 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ms5611_state *st = iio_priv(indio_dev);
-	s32 buf[4]; /* s32 (pressure) + s32 (temp) + 2 * s32 (timestamp) */
+	/* Ensure buffer elements are naturally aligned */
+	struct {
+		s32 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 	int ret;
 
 	mutex_lock(&st->lock);
-	ret = ms5611_read_temp_and_pressure(indio_dev, &buf[1], &buf[0]);
+	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
+					    &scan.channels[0]);
 	mutex_unlock(&st->lock);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
--

2.26.2

author maintainer Applied
#39 lore raw

Re: [PATCH 21/32] iio:pressure:ms5611 Fix buffer element alignment

Quoted 10 lines · On Sun, 7 Jun 2020 20:03:13 +0200 Tomasz Duszynski…
Quoted 9 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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. Here there is no data leak possibility so use an explicit structure on the stack to ensure alignment and nice readable fashion.

Quoted 8 lines
Quoted 5 lines

The forced alignment of ts isn't strictly necessary in this driver as the padding will be correct anyway (there isn't any). However it is probably less fragile to have it there and it acts as documentation of the requirement.

Looks good.

Applied to the fixes-togreg branch of iio.git and marked for stable. I'm picking up those patch in the series for which I have an ack to cut down on the number we need to consider in the next version.

Thanks,

Jonathan

Quoted 40 lines
Quoted 40 lines
Fixes 713bbb4efb9dc ("iio: pressure: ms5611: Add triggered buffer support")
---
 drivers/iio/pressure/ms5611_core.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/iio/pressure/ms5611_core.c +8 -4
index d451bb9dffc8..214b0d25f598 100644
@@ -212,16 +212,21 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ms5611_state *st = iio_priv(indio_dev);
-	s32 buf[4]; /* s32 (pressure) + s32 (temp) + 2 * s32 (timestamp) */
+	/* Ensure buffer elements are naturally aligned */
+	struct {
+		s32 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 	int ret;
 
 	mutex_lock(&st->lock);
-	ret = ms5611_read_temp_and_pressure(indio_dev, &buf[1], &buf[0]);
+	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
+					    &scan.channels[0]);
 	mutex_unlock(&st->lock);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
--

2.26.2

author maintainer
#40 lore raw

PATCH v2 22/32 iio:pressure:mpl3115 Force alignment of buffer

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

Whilst this is another case of the issue Lars reported with an array of elements of smaller than 8 bytes being passed to iio_push_to_buffers_with_timestamp, the solution here is a bit different from the other cases and relies on __aligned working on the stack (true since 4.6?)

This one is unusual. We have to do an explicit memset each time as we are reading 3 bytes into a potential 4 byte channel which may sometimes be a 2 byte channel depending on what is enabled. As such, moving the buffer to the heap in the iio_priv structure doesn't save us much. We can't use a nice explicit structure on the stack either as the data channels have different storage sizes and are all separately controlled.

Fixes cc26ad455f57 ("iio: Add Freescale MPL3115A2 pressure / temperature sensor driver")
Cc Peter Meerwald <[email protected]>
---
 drivers/iio/pressure/mpl3115.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/iio/pressure/mpl3115.c +2 -1
index ccdb0b70e48c..8a481dbe808c 100644
@@ -144,7 +144,8 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mpl3115_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 32-bit channel + 16-bit channel + padding + ts */
+	/* 32-bit channel + 16-bit channel + padding + ts */
+	u8 buffer[16] __aligned(8);
 	int ret, pos = 0;
 
 	mutex_lock(&data->lock);
Signature · 1 line
2.26.2
author maintainer
#41 lore raw

PATCH v2 23/32 iio:adc:ti-adc081c Fix alignment and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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().

This data is allocated with kzalloc so no data can leak apart from previous readings.

The eplicit alignment of ts is necessary to ensure correct padding on x86_32 where s64 is only aligned to 4 bytes.

Fixes 08e05d1fce5c (" ti-adc081c: Initial triggered buffer support")
---
 drivers/iio/adc/ti-adc081c.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/iio/adc/ti-adc081c.c +8 -3
index e44e7a40a36b..12b47dffeb3b 100644
@@ -33,6 +33,12 @@ struct adc081c {
 
 	/* 8, 10 or 12 */
 	int bits;
+
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		u16 channel;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 #define REG_CONV_RES 0x00
@@ -128,14 +134,13 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc081c *data = iio_priv(indio_dev);
-	u16 buf[8]; /* 2 bytes data + 6 bytes padding + 8 bytes timestamp */
 	int ret;
 
 	ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES);
 	if (ret < 0)
 		goto out;
-	buf[0] = ret;
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	data->scan.channel = ret;
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 out:
 	iio_trigger_notify_done(indio_dev->trig);
Signature · 1 line
2.26.2
author maintainer
#42 lore raw

PATCH v2 24/32 iio:adc:ti-adc084s021 Fix alignment and data leak issues.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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().

This data is allocated with kzalloc so no data can leak apart from previous readings.

The force alignment of ts is not strictly necessary in this case but reduces the fragility of the code.

Fixes 3691e5a69449 ("iio: adc: add driver for the ti-adc084s021 chip")
Cc Mårten Lindahl <[email protected]>
---
 drivers/iio/adc/ti-adc084s021.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/adc/ti-adc084s021.c +7 -3
index 376a0cf1f4ff..3ffbde379011 100644
@@ -25,6 +25,11 @@ struct adc084s021 {
 	struct spi_transfer spi_trans;
 	struct regulator *reg;
 	struct mutex lock;
+	/* Buffer used to align data */
+	struct {
+		__be16 channels[4];
+		s64 ts __aligned(8);
+	} scan;
 	/*
 	 * DMA (thus cache coherency maintenance) requires the
 	 * transfer buffers to live in their own cache line.
@@ -140,14 +145,13 @@ static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc)
 	struct iio_poll_func *pf = pollfunc;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc084s021 *adc = iio_priv(indio_dev);
-	__be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */
 
 	mutex_lock(&adc->lock);
 
-	if (adc084s021_adc_conversion(adc, &data) < 0)
+	if (adc084s021_adc_conversion(adc, adc->scan.channels) < 0)
 		dev_err(&adc->spi->dev, "Failed to read data\n");
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
 					   iio_get_time_ns(indio_dev));
 	mutex_unlock(&adc->lock);
 	iio_trigger_notify_done(indio_dev->trig);
Signature · 1 line
2.26.2
author maintainer
#43 lore raw

PATCH v2 25/32 iio:adc:ti-adc084s021 Tidy up endian types

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

By adding a few local variables and avoiding a void * for a parameter we can easily make all the endian types explicit and get rid of the warnings from sparse:

CHECK drivers/iio/adc/ti-adc084s021.c
drivers/iio/adc/ti-adc084s021.c:84:26: warning: incorrect type in assignment (different base types)
drivers/iio/adc/ti-adc084s021.c:84:26: expected unsigned short [usertype]
drivers/iio/adc/ti-adc084s021.c:84:26: got restricted __be16
drivers/iio/adc/ti-adc084s021.c:115:24: warning: cast to restricted __be16 drivers/iio/adc/ti-adc084s021.c:115:24: warning: cast to restricted __be16 drivers/iio/adc/ti-adc084s021.c:115:24: warning: cast to restricted __be16 drivers/iio/adc/ti-adc084s021.c:115:24: warning: cast to restricted __be16

---
 drivers/iio/adc/ti-adc084s021.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/iio/adc/ti-adc084s021.c +5 -5
index 3ffbde379011..b1448f49386b 100644
@@ -69,11 +69,10 @@ static const struct iio_chan_spec adc084s021_channels[] = {
  * @adc: The ADC SPI data.
  * @data: Buffer for converted data.
  */
-static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data)
+static int adc084s021_adc_conversion(struct adc084s021 *adc, __be16 *data)
 {
 	int n_words = (adc->spi_trans.len >> 1) - 1; /* Discard first word */
 	int ret, i = 0;
-	u16 *p = data;
 
 	/* Do the transfer */
 	ret = spi_sync(adc->spi, &adc->message);
@@ -81,7 +80,7 @@ static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data)
 		return ret;
 
 	for (; i < n_words; i++)
-		*(p + i) = adc->rx_buf[i + 1];
+		*(data + i) = adc->rx_buf[i + 1];
 
 	return ret;
 }
@@ -92,6 +91,7 @@ static int adc084s021_read_raw(struct iio_dev *indio_dev,
 {
 	struct adc084s021 *adc = iio_priv(indio_dev);
 	int ret;
+	__be16 be_val;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
@@ -106,13 +106,13 @@ static int adc084s021_read_raw(struct iio_dev *indio_dev,
 		}
 
 		adc->tx_buf[0] = channel->channel << 3;
-		ret = adc084s021_adc_conversion(adc, val);
+		ret = adc084s021_adc_conversion(adc, &be_val);
 		iio_device_release_direct_mode(indio_dev);
 		regulator_disable(adc->reg);
 		if (ret < 0)
 			return ret;
 
-		*val = be16_to_cpu(*val);
+		*val = be16_to_cpu(be_val);
 		*val = (*val >> channel->scan_type.shift) & 0xff;
 
 		return IIO_VAL_INT;
Signature · 1 line
2.26.2
author maintainer
#44 lore raw

PATCH v2 26/32 iio:adc:ti-ads1015 Fix buffer element alignment

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

Here we use an explicit structure and rely on that to enforce alignment on the stack. Note there was never a data leak here due to the explicit memset.

Explicit alignment of ts is needed to avoid incorrect padding on architectures which only enforce 4 byte alignment for s64 such as x86_32

Fixes ecc24e72f437 ("iio: adc: Add TI ADS1015 ADC driver support")
Cc Andy Shevchenko <[email protected]>
---
 drivers/iio/adc/ti-ads1015.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/iio/adc/ti-ads1015.c +8 -4
index 629c631e8f5c..6f4b54b97c5c 100644
@@ -385,10 +385,14 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ads1015_data *data = iio_priv(indio_dev);
-	s16 buf[8]; /* 1x s16 ADC val + 3x s16 padding +  4x s16 timestamp */
+	/* Ensure natural alignment for buffer elements */
+	struct {
+		s16 channel;
+		s64 ts __aligned(8);
+	} scan;
 	int chan, ret, res;
 
-	memset(buf, 0, sizeof(buf));
+	memset(&scan, 0, sizeof(scan));
 
 	mutex_lock(&data->lock);
 	chan = find_first_bit(indio_dev->active_scan_mask,
@@ -399,10 +403,10 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
 		goto err;
 	}
 
-	buf[0] = res;
+	scan.channel = res;
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
Signature · 1 line
2.26.2
author maintainer
#45 lore raw

PATCH v2 27/32 iio:adc:ti-ads124s08 Fix alignment and data leak issues.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

Fixes e717f8c6dfec ("iio: adc: Add the TI ads124s08 ADC code")
Cc Dan Murphy <[email protected]>
---
 drivers/iio/adc/ti-ads124s08.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/adc/ti-ads124s08.c +7 -3
index dacaa7255a3b..f9731e6a4260 100644
@@ -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);
Signature · 1 line
2.26.2
#46 lore raw

Re: [PATCH 27/32] iio:adc:ti-ads124s08 Fix alignment and data leak issues.

Quoted 12 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

drivers/iio/adc/ti-ads124s08.c struct ads124s_private {

Quoted 6 lines
drivers/iio/adc/ti-ads124s08.c +5 -0
+	/*
+	 * Used to correctly align data.
+	 * Ensure timestamp is naturally aligned.
+	 */
 
+	u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);

Can't you rather provide a struct as well?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#47 lore raw

Re: [PATCH 27/32] iio:adc:ti-ads124s08 Fix alignment and data leak issues.

Quoted 13 lines · On Mon, 8 Jun 2020 16:14:58 +0300 Andy Shevchenko…
Quoted 11 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

Quoted 9 lines

drivers/iio/adc/ti-ads124s08.c struct ads124s_private {

Quoted 6 lines
drivers/iio/adc/ti-ads124s08.c +5 -0
+	/*
+	 * Used to correctly align data.
+	 * Ensure timestamp is naturally aligned.
+	 */  
 
+	u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);  

Can't you rather provide a struct as well?

Not without giving a false impression of where the time stamp is in the resulting buffer.

I'm not keen to do that because it'll lead to people fundamentally misunderstanding the dynamic nature of IIO buffer packing.

Here it could start at byte 8, 16, 24, 32, 48, 64 I think.

It's more than possible I've gotten one of these wrong and missed a restriction on the layout in a given device though!

Jonathan

#48 lore raw

Re: [PATCH 27/32] iio:adc:ti-ads124s08 Fix alignment and data leak issues.

Quoted 25 lines · Jonathan Cameron
Quoted 13 lines · On Mon, 8 Jun 2020 16:14:58 +0300 Andy Shevchenko…
Quoted 11 lines · Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

Quoted 9 lines

drivers/iio/adc/ti-ads124s08.c struct ads124s_private {

Quoted 6 lines
drivers/iio/adc/ti-ads124s08.c +5 -0
+	/*
+	 * Used to correctly align data.
+	 * Ensure timestamp is naturally aligned.
+	 */  
 
+	u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);  

Can't you rather provide a struct as well?

Quoted 7 lines

Not without giving a false impression of where the time stamp is in the resulting buffer.

I'm not keen to do that because it'll lead to people fundamentally misunderstanding the dynamic nature of IIO buffer packing.

Here it could start at byte 8, 16, 24, 32, 48, 64 I think.

I see, thanks for explanation!
Same for the other comment.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#49 lore raw

PATCH v2 28/32 iio:adc:ti-ads8688 Fix alignment and potential data leak issue

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 32 byte 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.

Fixes 2a86487786b5 ("iio: adc: ti-ads8688: add trigger and buffer support")
Cc Sean Nyekjaer <[email protected]>
---
 drivers/iio/adc/ti-ads8688.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/iio/adc/ti-ads8688.c +9 -3
index 011e5c8b5afd..2b4bce0cac17 100644
@@ -68,6 +68,12 @@ struct ads8688_state {
 	struct regulator		*reg;
 	unsigned int			vref_mv;
 	enum ads8688_range		range[8];
+	/*
+	 * Used to align data for pushing to IIO.
+	 * Ensure natural alignment of timestamps
+	 */
+	u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);
+
 	union {
 		__be32 d32;
 		u8 d8[4];
@@ -383,17 +389,17 @@ static irqreturn_t ads8688_trigger_handler(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
-	u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
+	struct ads8688_state *st = iio_priv(indio_dev);
 	int i, j = 0;
 
 	for (i = 0; i < indio_dev->masklength; i++) {
 		if (!test_bit(i, indio_dev->active_scan_mask))
 			continue;
-		buffer[j] = ads8688_read(indio_dev, i);
+		st->buffer[j] = ads8688_read(indio_dev, i);
 		j++;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, st->buffer,
 			iio_get_time_ns(indio_dev));
 
 	iio_trigger_notify_done(indio_dev->trig);
Signature · 1 line
2.26.2
author maintainer
#50 lore raw

PATCH v2 29/32 iio:adc:ti-adc0832 Fix alignment issue with timestamp

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

We fix this 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. Note that previously no data could leak 'including' previous readings but I don't think it is an issue to potentially leak them like this now does.

Fixes 815bbc87462a ("iio: ti-adc0832: add triggered buffer support")
Cc Akinobu Mita <[email protected]>
---
 drivers/iio/adc/ti-adc0832.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/iio/adc/ti-adc0832.c +4 -3
index 054db3425afa..a419c697272a 100644
@@ -28,6 +28,8 @@ struct adc0832 {
 	struct regulator *reg;
 	struct mutex lock;
 	u8 mux_bits;
+	/* 16x 1 byte ADC data + 8 bytes timestamp */
+	u8 data[24] __aligned(8);
 
 	u8 tx_buf[2] ____cacheline_aligned;
 	u8 rx_buf[2];
@@ -199,7 +201,6 @@ static irqreturn_t adc0832_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc0832 *adc = iio_priv(indio_dev);
-	u8 data[24] = { }; /* 16x 1 byte ADC data + 8 bytes timestamp */
 	int scan_index;
 	int i = 0;
 
@@ -217,10 +218,10 @@ static irqreturn_t adc0832_trigger_handler(int irq, void *p)
 			goto out;
 		}
 
-		data[i] = ret;
+		adc->data[i] = ret;
 		i++;
 	}
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, adc->data,
 					   iio_get_time_ns(indio_dev));
 out:
 	mutex_unlock(&adc->lock);
Signature · 1 line
2.26.2
author maintainer
#51 lore raw

PATCH v2 30/32 iio:adc:ti-adc12138 Fix alignment issue with timestamp

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

We move 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. Note that previously no leak at all could occur, but previous readings should never be a problem.

Fixes 50a6edb1b6e0 ("iio: adc: add ADC12130/ADC12132/ADC12138 ADC driver")
Cc Akinobu Mita <[email protected]>
---
 drivers/iio/adc/ti-adc12138.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/iio/adc/ti-adc12138.c +5 -4
index e485719cd2c4..16f4fd7a04d9 100644
@@ -47,6 +47,8 @@ struct adc12138 {
 	struct completion complete;
 	/* The number of cclk periods for the S/H's acquisition time */
 	unsigned int acquisition_time;
+	 /* 16x 2 bytes ADC data + 8 bytes timestamp */
+	__be16 data[20] __aligned(8);
 
 	u8 tx_buf[2] ____cacheline_aligned;
 	u8 rx_buf[2];
@@ -329,7 +331,6 @@ static irqreturn_t adc12138_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc12138 *adc = iio_priv(indio_dev);
-	__be16 data[20] = { }; /* 16x 2 bytes ADC data + 8 bytes timestamp */
 	__be16 trash;
 	int ret;
 	int scan_index;
@@ -345,7 +346,7 @@ static irqreturn_t adc12138_trigger_handler(int irq, void *p)
 		reinit_completion(&adc->complete);
 
 		ret = adc12138_start_and_read_conv(adc, scan_chan,
-						   i ? &data[i - 1] : &trash);
+					i ? &adc->data[i - 1] : &trash);
 		if (ret) {
 			dev_warn(&adc->spi->dev,
 				 "failed to start conversion\n");
@@ -362,7 +363,7 @@ static irqreturn_t adc12138_trigger_handler(int irq, void *p)
 	}
 
 	if (i) {
-		ret = adc12138_read_conv_data(adc, &data[i - 1]);
+		ret = adc12138_read_conv_data(adc, &adc->data[i - 1]);
 		if (ret) {
 			dev_warn(&adc->spi->dev,
 				 "failed to get conversion data\n");
@@ -370,7 +371,7 @@ static irqreturn_t adc12138_trigger_handler(int irq, void *p)
 		}
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, adc->data,
 					   iio_get_time_ns(indio_dev));
 out:
 	mutex_unlock(&adc->lock);
Signature · 1 line
2.26.2
author maintainer
#52 lore raw

PATCH v2 31/32 iio:adc:ina2xx Fix timestamp alignment issue.

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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 a 32 byte 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.

If we want this in older stables will need manual backport due to driver reworks.

Fixes c43a102e67db ("iio: ina2xx: add support for TI INA2xx Power Monitors")
Cc Stefan Brüns <[email protected]>
Cc Marc Titinger <[email protected]>
---
 drivers/iio/adc/ina2xx-adc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/iio/adc/ina2xx-adc.c +4 -4
index 467f48b6f451..6f466d42c520 100644
@@ -146,6 +146,8 @@ struct ina2xx_chip_info {
 	int range_vbus; /* Bus voltage maximum in V */
 	int pga_gain_vshunt; /* Shunt voltage PGA gain */
 	bool allow_async_readout;
+	/* data buffer needs space for channel data and timestap */
+	unsigned short data[4 + sizeof(s64)/sizeof(short)] __aligned(8);
 };
 
 static const struct ina2xx_config ina2xx_config[] = {
@@ -738,8 +740,6 @@ static int ina2xx_conversion_ready(struct iio_dev *indio_dev)
 static int ina2xx_work_buffer(struct iio_dev *indio_dev)
 {
 	struct ina2xx_chip_info *chip = iio_priv(indio_dev);
-	/* data buffer needs space for channel data and timestap */
-	unsigned short data[4 + sizeof(s64)/sizeof(short)];
 	int bit, ret, i = 0;
 	s64 time;
 
@@ -758,10 +758,10 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
 		if (ret < 0)
 			return ret;
 
-		data[i++] = val;
+		chip->data[i++] = val;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data, time);
+	iio_push_to_buffers_with_timestamp(indio_dev, chip->data, time);
 
 	return 0;
 };
Signature · 1 line
2.26.2
author maintainer
#53 lore raw

PATCH v2 32/32 iio:adc:max1118 Fix alignment of timestamp and data leak issues

In reply to Jonathan Cameron

From: Jonathan Cameron <[email protected]>

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.

This data is allocated with kzalloc so no data can leak apart from previous readings.

The explicit alignment of ts is necessary to ensure correct padding on architectures where s64 is only 4 bytes aligned such as x86_32.

Fixes a9e9c7153e96 ("iio: adc: add max1117/max1118/max1119 ADC driver")
Cc Akinobu Mita <[email protected]>
---
 drivers/iio/adc/max1118.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/iio/adc/max1118.c +7 -3
index 273fbea2a515..af68d6165b68 100644
@@ -35,6 +35,11 @@ struct max1118 {
 	struct spi_device *spi;
 	struct mutex lock;
 	struct regulator *reg;
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		u8 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 
 	u8 data ____cacheline_aligned;
 };
@@ -165,7 +170,6 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct max1118 *adc = iio_priv(indio_dev);
-	u8 data[16] = { }; /* 2x 8-bit ADC data + padding + 8 bytes timestamp */
 	int scan_index;
 	int i = 0;
 
@@ -183,10 +187,10 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
 			goto out;
 		}
 
-		data[i] = ret;
+		adc->scan.channels[i] = ret;
 		i++;
 	}
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
 					   iio_get_time_ns(indio_dev));
 out:
 	mutex_unlock(&adc->lock);
Signature · 1 line
2.26.2