All of lore.kernel.org
 help / color / mirror / Atom feed
* re: STAGING:iio:light: fix ISL29018 init to handle brownout
@ 2011-08-26  1:15 Dan Carpenter
  2011-08-26  5:27 ` Grant Grundler
  2011-08-26 21:58 ` Grant Grundler
  0 siblings, 2 replies; 9+ messages in thread
From: Dan Carpenter @ 2011-08-26  1:15 UTC (permalink / raw)
  To: Grant Grundler; +Cc: linux-iio, devel

Hi Grant,

There is a memory corruption bug in 176f9f29cec9 "STAGING:iio:light:
fix ISL29018 init to handle brownout".

In isl29018_chip_init() we call:
        status = isl29018_write_data(client, ISL29018_REG_TEST, 0,               
                                ISL29018_TEST_MASK, ISL29018_TEST_SHIFT);        

where ISL29018_REG_TEST is 8.

In isl29018_write_data() it uses reg (ISL29018_REG_TEST) as the
offset into the ->reg_cache[] array:
	chip->reg_cache[reg] = regval;

But ->reg_cache[] only has 3 elements, so we're past the end of the
array.

I don't know the code well enough to fix this.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-26  1:15 STAGING:iio:light: fix ISL29018 init to handle brownout Dan Carpenter
@ 2011-08-26  5:27 ` Grant Grundler
  2011-08-26 21:58 ` Grant Grundler
  1 sibling, 0 replies; 9+ messages in thread
From: Grant Grundler @ 2011-08-26  5:27 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linux-iio, devel

On Thu, Aug 25, 2011 at 6:15 PM, Dan Carpenter <error27@gmail.com> wrot=
e:
> Hi Grant,
>
> There is a memory corruption bug in 176f9f29cec9 "STAGING:iio:light:
> fix ISL29018 init to handle brownout".
>
> In isl29018_chip_init() we call:
> =C2=A0 =C2=A0 =C2=A0 =C2=A0status =3D isl29018_write_data(client, ISL=
29018_REG_TEST, 0,
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ISL29018_TEST_MASK, ISL29018_=
TEST_SHIFT);
>
> where ISL29018_REG_TEST is 8.
>
> In isl29018_write_data() it uses reg (ISL29018_REG_TEST) as the
> offset into the ->reg_cache[] array:
> =C2=A0 =C2=A0 =C2=A0 =C2=A0chip->reg_cache[reg] =3D regval;
>
> But ->reg_cache[] only has 3 elements, so we're past the end of the
> array.

Wow! Thanks! I'll look at the code in the morning and suggest a fix.


> I don't know the code well enough to fix this.

No problem - I'm happy you spotted this.

My initial suggestion for a fix is to just not reference reg_cache if
"reg" exceeds the size of reg_cache. In other words, don't cache those
values. This should normally work well since we don't other touch that
register in the driver AFAICT.  But I'll review the code some more
tomorrow before submitting a fix.

cheers,
grant

>
> regards,
> dan carpenter
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-26  1:15 STAGING:iio:light: fix ISL29018 init to handle brownout Dan Carpenter
  2011-08-26  5:27 ` Grant Grundler
@ 2011-08-26 21:58 ` Grant Grundler
  2011-08-26 22:18   ` Dan Carpenter
  2011-08-30 10:05   ` Jonathan Cameron
  1 sibling, 2 replies; 9+ messages in thread
From: Grant Grundler @ 2011-08-26 21:58 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linux-iio, devel

[-- Attachment #1: Type: text/plain, Size: 1270 bytes --]

On Thu, Aug 25, 2011 at 6:15 PM, Dan Carpenter <error27@gmail.com> wrote:
...
> In isl29018_write_data() it uses reg (ISL29018_REG_TEST) as the
> offset into the ->reg_cache[] array:
>        chip->reg_cache[reg] = regval;
>
> But ->reg_cache[] only has 3 elements, so we're past the end of the
> array.

Dan,
I've attached a preliminary patch to fix this that applies on top of
176f9f29cec9 "STAGING:iio:light:
fix ISL29018 init to handle brownout".  This patch applies cleanly to
the 2.6.38-based chromium.org tree.

In a nutshell, the attached patch implements what I was thinking of
last night: don't cache REG_TEST.

I did change one basic behavior that I think was also broken: cache
the value regardless of if the transaction completed successfully or
not. For registers where we are frobbing bits, the later write to the
same register  might succeed and things will work anyway despite the
transient failure. If I'm wrong, please comment and I'll repost with
original behavior.

I also noticed the original code had an "off-by-one" error in the
allocation of reg_cache[] (allocated 3 but indexed up to offset +3).

I'll submit a cleaned up version that should cleanly apply to gregkh's
staging-2.6 tree.

thanks again!
grant

[-- Attachment #2: 2.6.38-isl29018_reg_cache-01 --]
[-- Type: application/octet-stream, Size: 1801 bytes --]

Fix out-of-bounds reference to reg_cache[]

Simple fix is to just not cache REG_TEST (offset 8). It doesn't help anyway
since we write all 8 bits exactly once (at resume/init time).

Also fix an "off-by-one" allocation of reg_cache[] array size that
was in the original code before I touched it.

Reported-by: Dan Carpenter <error27@gmail.com>
Signed-off-by: Grant Grundler <grundler@chromium.org>

----
Thanks again to Dan Carpenter for spotting the out-of-bounds array reference.

diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 0f97734..a5259ff 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -51,7 +51,7 @@
 
 #define ISL29018_REG_ADD_DATA_LSB	0x02
 #define ISL29018_REG_ADD_DATA_MSB	0x03
-#define ISL29018_MAX_REGS		ISL29018_REG_ADD_DATA_MSB
+#define ISL29018_MAX_REGS		ISL29018_REG_ADD_DATA_MSB+1
 
 #define ISL29018_REG_TEST		0x08
 #define ISL29018_TEST_SHIFT		0
@@ -71,22 +71,23 @@ struct isl29018_chip {
 static int isl29018_write_data(struct i2c_client *client, u8 reg,
 			u8 val, u8 mask, u8 shift)
 {
-	u8 regval;
-	int ret = 0;
+	u8 regval = val;
+	int ret;
 	struct isl29018_chip *chip = i2c_get_clientdata(client);
 
-	regval = chip->reg_cache[reg];
-	regval &= ~mask;
-	regval |= val << shift;
+	/* don't cache REG_TEST */
+	if (reg < ISL29018_MAX_REGS) {
+		regval = chip->reg_cache[reg];
+		regval &= ~mask;
+		regval |= val << shift;
+		chip->reg_cache[reg] = regval;
+	}
 
 	ret = i2c_smbus_write_byte_data(client, reg, regval);
-	if (ret) {
+	if (ret)
 		dev_err(&client->dev, "Write to device fails status %x\n", ret);
-		return ret;
-	}
-	chip->reg_cache[reg] = regval;
 
-	return 0;
+	return ret;
 }
 
 static int isl29018_set_range(struct i2c_client *client, unsigned long range,

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-26 21:58 ` Grant Grundler
@ 2011-08-26 22:18   ` Dan Carpenter
  2011-08-26 22:42     ` Grant Grundler
  2011-08-30 10:05   ` Jonathan Cameron
  1 sibling, 1 reply; 9+ messages in thread
From: Dan Carpenter @ 2011-08-26 22:18 UTC (permalink / raw)
  To: Grant Grundler; +Cc: linux-iio, devel

It looks good to me, but I don't know anything about the iio code.
Jonathan will let you know if there is a problem.  :)

This is minor thing, but checkpatch complains that:
+#define ISL29018_MAX_REGS              ISL29018_REG_ADD_DATA_MSB+1
should be written as:
+#define ISL29018_MAX_REGS              (ISL29018_REG_ADD_DATA_MSB + 1)

Thanks Grant.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-26 22:18   ` Dan Carpenter
@ 2011-08-26 22:42     ` Grant Grundler
  0 siblings, 0 replies; 9+ messages in thread
From: Grant Grundler @ 2011-08-26 22:42 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linux-iio, devel

On Fri, Aug 26, 2011 at 3:18 PM, Dan Carpenter <error27@gmail.com> wrot=
e:
> It looks good to me, but I don't know anything about the iio code.
> Jonathan will let you know if there is a problem. =C2=A0:)

I'm hoping so. :)  Thanks for reviewing.

>
> This is minor thing, but checkpatch complains that:
> +#define ISL29018_MAX_REGS =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0ISL29018_REG_ADD_DATA_MSB+1
> should be written as:
> +#define ISL29018_MAX_REGS =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0(ISL29018_REG_ADD_DATA_MSB + 1)

ah...I didn't run check_patch. /o\
I'll include that in the version I send to gregkh.

cheers,
grant

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-26 21:58 ` Grant Grundler
  2011-08-26 22:18   ` Dan Carpenter
@ 2011-08-30 10:05   ` Jonathan Cameron
  2011-08-30 16:14     ` Grant Grundler
  1 sibling, 1 reply; 9+ messages in thread
From: Jonathan Cameron @ 2011-08-30 10:05 UTC (permalink / raw)
  To: Grant Grundler; +Cc: Dan Carpenter, linux-iio, devel

On 08/26/11 22:58, Grant Grundler wrote:
> On Thu, Aug 25, 2011 at 6:15 PM, Dan Carpenter <error27@gmail.com> wrote:
> ...
>> In isl29018_write_data() it uses reg (ISL29018_REG_TEST) as the
>> offset into the ->reg_cache[] array:
>>        chip->reg_cache[reg] = regval;
>>
>> But ->reg_cache[] only has 3 elements, so we're past the end of the
>> array.
> 
> Dan,
> I've attached a preliminary patch to fix this that applies on top of
> 176f9f29cec9 "STAGING:iio:light:
> fix ISL29018 init to handle brownout".  This patch applies cleanly to
> the 2.6.38-based chromium.org tree.
> 
> In a nutshell, the attached patch implements what I was thinking of
> last night: don't cache REG_TEST.
> 
> I did change one basic behavior that I think was also broken: cache
> the value regardless of if the transaction completed successfully or
> not. 
Don't do that.  That means userspace will get an invalid value if it reads
in the meantime. If you have an error on a hardware bus - tell userspace about
it and don't 'guess' what is in the register.

Otherwise patch looks fine to me.
>For registers where we are frobbing bits, the later write to the
> same register  might succeed and things will work anyway despite the
> transient failure. If I'm wrong, please comment and I'll repost with
> original behavior.
> 
> I also noticed the original code had an "off-by-one" error in the
> allocation of reg_cache[] (allocated 3 but indexed up to offset +3).
> 
> I'll submit a cleaned up version that should cleanly apply to gregkh's
> staging-2.6 tree.
> 
> thanks again!
> grant


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-30 10:05   ` Jonathan Cameron
@ 2011-08-30 16:14     ` Grant Grundler
  2011-08-30 16:31       ` Jonathan Cameron
  0 siblings, 1 reply; 9+ messages in thread
From: Grant Grundler @ 2011-08-30 16:14 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: Dan Carpenter, linux-iio, devel

On Tue, Aug 30, 2011 at 3:05 AM, Jonathan Cameron <jic23@cam.ac.uk> wrote:
....
>> I did change one basic behavior that I think was also broken: cache
>> the value regardless of if the transaction completed successfully or
>> not.
> Don't do that. =C2=A0That means userspace will get an invalid value if it=
 reads
> in the meantime. If you have an error on a hardware bus - tell userspace =
about
> it and don't 'guess' what is in the register.

Ah ok - I didn't know this was part of the path to/from user space.

>
> Otherwise patch looks fine to me.

OK - I'll restore previous behavior and submit another patch.

cheers!
grant

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-30 16:14     ` Grant Grundler
@ 2011-08-30 16:31       ` Jonathan Cameron
  2011-08-30 16:45         ` Grant Grundler
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Cameron @ 2011-08-30 16:31 UTC (permalink / raw)
  To: Grant Grundler; +Cc: Dan Carpenter, linux-iio, devel

On 08/30/11 17:14, Grant Grundler wrote:
> On Tue, Aug 30, 2011 at 3:05 AM, Jonathan Cameron <jic23@cam.ac.uk> wrote:
> ....
>>> I did change one basic behavior that I think was also broken: cache
>>> the value regardless of if the transaction completed successfully or
>>> not.
>> Don't do that.  That means userspace will get an invalid value if it reads
>> in the meantime. If you have an error on a hardware bus - tell userspace about
>> it and don't 'guess' what is in the register.
> 
> Ah ok - I didn't know this was part of the path to/from user space.
It plausibly isn't, I didn't go over it closely enough to be sure.
Even if not, it's a nasty complexity that will bite someone at some stage.
Mostly comes down to code doing what other code does in the same situation
rather than trying to be clever.


> 
>>
>> Otherwise patch looks fine to me.
> 
> OK - I'll restore previous behavior and submit another patch.
> 
> cheers!
> grant
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: STAGING:iio:light: fix ISL29018 init to handle brownout
  2011-08-30 16:31       ` Jonathan Cameron
@ 2011-08-30 16:45         ` Grant Grundler
  0 siblings, 0 replies; 9+ messages in thread
From: Grant Grundler @ 2011-08-30 16:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: Dan Carpenter, linux-iio, devel

On Tue, Aug 30, 2011 at 9:31 AM, Jonathan Cameron <jic23@cam.ac.uk> wrote:
> On 08/30/11 17:14, Grant Grundler wrote:
>> On Tue, Aug 30, 2011 at 3:05 AM, Jonathan Cameron <jic23@cam.ac.uk> wrot=
e:
>> ....
>>>> I did change one basic behavior that I think was also broken: cache
>>>> the value regardless of if the transaction completed successfully or
>>>> not.
>>> Don't do that. =C2=A0That means userspace will get an invalid value if =
it reads
>>> in the meantime. If you have an error on a hardware bus - tell userspac=
e about
>>> it and don't 'guess' what is in the register.
>>
>> Ah ok - I didn't know this was part of the path to/from user space.
> It plausibly isn't, I didn't go over it closely enough to be sure.

Ok. After thinking about it more, it might not matter anyway.

> Even if not, it's a nasty complexity that will bite someone at some stage=
.
> Mostly comes down to code doing what other code does in the same situatio=
n
> rather than trying to be clever.

The whole error handling path one ugly bit of "nasty complexity". If a regi=
ster
write fails, the register contents will be unknown. We will have no idea wh=
at
value is in the register or if the device is even still alive.
The cached value can't represent "known HW state" at that point and should
probably be marked "invalid" until either the value is succesfully
read or the next
write succeeds.

BTW, I didn't consider this particularly clever - just the code was
easier to read. :)

I don't think it really matters how the "cached value" is handled as
long as the error gets returned.  I'm just going to implement whatever
you prefer. :)

cheers,
grant

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-08-30 16:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-26  1:15 STAGING:iio:light: fix ISL29018 init to handle brownout Dan Carpenter
2011-08-26  5:27 ` Grant Grundler
2011-08-26 21:58 ` Grant Grundler
2011-08-26 22:18   ` Dan Carpenter
2011-08-26 22:42     ` Grant Grundler
2011-08-30 10:05   ` Jonathan Cameron
2011-08-30 16:14     ` Grant Grundler
2011-08-30 16:31       ` Jonathan Cameron
2011-08-30 16:45         ` Grant Grundler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.