Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f566b62 authored by Wei Yongjun's avatar Wei Yongjun Committed by Greg Kroah-Hartman
Browse files

iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw



[ Upstream commit fc92d9e3de0b2d30a3ccc08048a5fad533e4672b ]

KASAN report out-of-bounds read as follows:

BUG: KASAN: global-out-of-bounds in afe4404_read_raw+0x2ce/0x380
Read of size 4 at addr ffffffffc00e4658 by task cat/278

Call Trace:
 afe4404_read_raw
 iio_read_channel_info
 dev_attr_show

The buggy address belongs to the variable:
 afe4404_channel_leds+0x18/0xffffffffffffe9c0

This issue can be reproduce by singe command:

 $ cat /sys/bus/i2c/devices/0-0058/iio\:device0/in_intensity6_raw

The array size of afe4404_channel_leds and afe4404_channel_offdacs
are less than channels, so access with chan->address cause OOB read
in afe4404_[read|write]_raw. Fix it by moving access before use them.

Fixes: b36e8257 ("iio: health/afe440x: Use regmap fields")
Signed-off-by: default avatarWei Yongjun <weiyongjun1@huawei.com>
Acked-by: default avatarAndrew Davis <afd@ti.com>
Link: https://lore.kernel.org/r/20221107152010.95937-1-weiyongjun@huaweicloud.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 2d6a4370
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -250,20 +250,20 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
			    int *val, int *val2, long mask)
{
	struct afe4404_data *afe = iio_priv(indio_dev);
	unsigned int value_reg = afe4404_channel_values[chan->address];
	unsigned int led_field = afe4404_channel_leds[chan->address];
	unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
	unsigned int value_reg, led_field, offdac_field;
	int ret;

	switch (chan->type) {
	case IIO_INTENSITY:
		switch (mask) {
		case IIO_CHAN_INFO_RAW:
			value_reg = afe4404_channel_values[chan->address];
			ret = regmap_read(afe->regmap, value_reg, val);
			if (ret)
				return ret;
			return IIO_VAL_INT;
		case IIO_CHAN_INFO_OFFSET:
			offdac_field = afe4404_channel_offdacs[chan->address];
			ret = regmap_field_read(afe->fields[offdac_field], val);
			if (ret)
				return ret;
@@ -273,6 +273,7 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
	case IIO_CURRENT:
		switch (mask) {
		case IIO_CHAN_INFO_RAW:
			led_field = afe4404_channel_leds[chan->address];
			ret = regmap_field_read(afe->fields[led_field], val);
			if (ret)
				return ret;
@@ -295,19 +296,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev,
			     int val, int val2, long mask)
{
	struct afe4404_data *afe = iio_priv(indio_dev);
	unsigned int led_field = afe4404_channel_leds[chan->address];
	unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
	unsigned int led_field, offdac_field;

	switch (chan->type) {
	case IIO_INTENSITY:
		switch (mask) {
		case IIO_CHAN_INFO_OFFSET:
			offdac_field = afe4404_channel_offdacs[chan->address];
			return regmap_field_write(afe->fields[offdac_field], val);
		}
		break;
	case IIO_CURRENT:
		switch (mask) {
		case IIO_CHAN_INFO_RAW:
			led_field = afe4404_channel_leds[chan->address];
			return regmap_field_write(afe->fields[led_field], val);
		}
		break;