]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
iio:light:max44000 Fix timestamp alignment and prevent data leak.
authorJonathan Cameron <Jonathan.Cameron@huawei.com>
Wed, 22 Jul 2020 15:50:45 +0000 (16:50 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 23 Sep 2020 08:46:29 +0000 (10:46 +0200)
commit 523628852a5f5f34a15252b2634d0498d3cfb347 upstream.

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")
Reported-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: <Stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/iio/light/max44000.c

index 81bd8e8da4a69af929760bfe1c12716fe16de972..255b932fc21df82cfef3a47c7f869c15e4404106 100644 (file)
 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 */
@@ -492,7 +497,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;
@@ -502,17 +506,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;