Commit 3d2562c0 authored by Wei Yongjun's avatar Wei Yongjun Committed by Lin Ruifeng
Browse files

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

stable inclusion
from stable-v4.19.268
commit f5575041ec15310bdc50c42b8b22118cc900226e
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAYREK
CVE: CVE-2022-49032

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=f5575041ec15310bdc50c42b8b22118cc900226e



--------------------------------

[ Upstream commit fc92d9e3 ]

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>
Signed-off-by: default avatarLin Ruifeng <linruifeng4@huawei.com>
parent e73db5f1
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -256,20 +256,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;
@@ -279,6 +279,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;
@@ -301,19 +302,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;