iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw
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: b36e825764
("iio: health/afe440x: Use regmap fields")
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Acked-by: Andrew Davis <afd@ti.com>
Link: https://lore.kernel.org/r/20221107152010.95937-1-weiyongjun@huaweicloud.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
58143c1ed5
commit
fc92d9e3de
|
@ -250,20 +250,20 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
|
||||||
int *val, int *val2, long mask)
|
int *val, int *val2, long mask)
|
||||||
{
|
{
|
||||||
struct afe4404_data *afe = iio_priv(indio_dev);
|
struct afe4404_data *afe = iio_priv(indio_dev);
|
||||||
unsigned int value_reg = afe4404_channel_values[chan->address];
|
unsigned int value_reg, led_field, offdac_field;
|
||||||
unsigned int led_field = afe4404_channel_leds[chan->address];
|
|
||||||
unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (chan->type) {
|
switch (chan->type) {
|
||||||
case IIO_INTENSITY:
|
case IIO_INTENSITY:
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_RAW:
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
value_reg = afe4404_channel_values[chan->address];
|
||||||
ret = regmap_read(afe->regmap, value_reg, val);
|
ret = regmap_read(afe->regmap, value_reg, val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
return IIO_VAL_INT;
|
return IIO_VAL_INT;
|
||||||
case IIO_CHAN_INFO_OFFSET:
|
case IIO_CHAN_INFO_OFFSET:
|
||||||
|
offdac_field = afe4404_channel_offdacs[chan->address];
|
||||||
ret = regmap_field_read(afe->fields[offdac_field], val);
|
ret = regmap_field_read(afe->fields[offdac_field], val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -273,6 +273,7 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
|
||||||
case IIO_CURRENT:
|
case IIO_CURRENT:
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_RAW:
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
led_field = afe4404_channel_leds[chan->address];
|
||||||
ret = regmap_field_read(afe->fields[led_field], val);
|
ret = regmap_field_read(afe->fields[led_field], val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -295,19 +296,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev,
|
||||||
int val, int val2, long mask)
|
int val, int val2, long mask)
|
||||||
{
|
{
|
||||||
struct afe4404_data *afe = iio_priv(indio_dev);
|
struct afe4404_data *afe = iio_priv(indio_dev);
|
||||||
unsigned int led_field = afe4404_channel_leds[chan->address];
|
unsigned int led_field, offdac_field;
|
||||||
unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
|
|
||||||
|
|
||||||
switch (chan->type) {
|
switch (chan->type) {
|
||||||
case IIO_INTENSITY:
|
case IIO_INTENSITY:
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_OFFSET:
|
case IIO_CHAN_INFO_OFFSET:
|
||||||
|
offdac_field = afe4404_channel_offdacs[chan->address];
|
||||||
return regmap_field_write(afe->fields[offdac_field], val);
|
return regmap_field_write(afe->fields[offdac_field], val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IIO_CURRENT:
|
case IIO_CURRENT:
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_RAW:
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
led_field = afe4404_channel_leds[chan->address];
|
||||||
return regmap_field_write(afe->fields[led_field], val);
|
return regmap_field_write(afe->fields[led_field], val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue