diff mbox series

i2c: i801: Fix memory corruption in i801_isr_byte_done()

Message ID 20200114073406.qaq3hbrhtx76fkes@kili.mountain
State Rejected
Headers show
Series i2c: i801: Fix memory corruption in i801_isr_byte_done() | expand

Commit Message

Dan Carpenter Jan. 14, 2020, 7:34 a.m. UTC
Assigning "priv->data[-1] = priv->len;" obviously doesn't make sense.
What it does is it ends up corrupting the last byte of priv->len so
priv->len becomes a very high number.

Reported-by: syzbot+ed71512d469895b5b34e@syzkaller.appspotmail.com
Fixes: d3ff6ce40031 ("i2c-i801: Enable IRQ for byte_by_byte transactions")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
Untested.

 drivers/i2c/busses/i2c-i801.c | 1 -
 1 file changed, 1 deletion(-)

Comments

Wolfram Sang Feb. 22, 2020, 12:45 p.m. UTC | #1
On Tue, Jan 14, 2020 at 10:34:06AM +0300, Dan Carpenter wrote:
> Assigning "priv->data[-1] = priv->len;" obviously doesn't make sense.
> What it does is it ends up corrupting the last byte of priv->len so
> priv->len becomes a very high number.
> 
> Reported-by: syzbot+ed71512d469895b5b34e@syzkaller.appspotmail.com
> Fixes: d3ff6ce40031 ("i2c-i801: Enable IRQ for byte_by_byte transactions")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---

Daniel, Jean: what do you think?
Also, adding Jarkko to CC who works a lot with this driver...

> Untested.
> 
>  drivers/i2c/busses/i2c-i801.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
> index f5e69fe56532..420d8025901e 100644
> --- a/drivers/i2c/busses/i2c-i801.c
> +++ b/drivers/i2c/busses/i2c-i801.c
> @@ -584,7 +584,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
>  					"SMBus block read size is %d\n",
>  					priv->len);
>  			}
> -			priv->data[-1] = priv->len;
>  		}
>  
>  		/* Read next byte */
> -- 
> 2.11.0
>
Wolfram Sang March 20, 2020, 2:57 p.m. UTC | #2
On Sat, Feb 22, 2020 at 01:45:23PM +0100, Wolfram Sang wrote:
> On Tue, Jan 14, 2020 at 10:34:06AM +0300, Dan Carpenter wrote:
> > Assigning "priv->data[-1] = priv->len;" obviously doesn't make sense.
> > What it does is it ends up corrupting the last byte of priv->len so
> > priv->len becomes a very high number.
> > 
> > Reported-by: syzbot+ed71512d469895b5b34e@syzkaller.appspotmail.com
> > Fixes: d3ff6ce40031 ("i2c-i801: Enable IRQ for byte_by_byte transactions")
> > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> > ---
> 
> Daniel, Jean: what do you think?
> Also, adding Jarkko to CC who works a lot with this driver...

Ping. Adding more people...

> 
> > Untested.
> > 
> >  drivers/i2c/busses/i2c-i801.c | 1 -
> >  1 file changed, 1 deletion(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
> > index f5e69fe56532..420d8025901e 100644
> > --- a/drivers/i2c/busses/i2c-i801.c
> > +++ b/drivers/i2c/busses/i2c-i801.c
> > @@ -584,7 +584,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
> >  					"SMBus block read size is %d\n",
> >  					priv->len);
> >  			}
> > -			priv->data[-1] = priv->len;
> >  		}
> >  
> >  		/* Read next byte */
> > -- 
> > 2.11.0
> >
Jean Delvare March 22, 2020, 6:08 p.m. UTC | #3
Hi Wolfram,

Can you please bounce the previous messages in this thread to me? I was
apparently not Cc'd so I'm missing the context.

Thanks,
Jean

On Fri, 20 Mar 2020 15:57:48 +0100, Wolfram Sang wrote:
> On Sat, Feb 22, 2020 at 01:45:23PM +0100, Wolfram Sang wrote:
> > On Tue, Jan 14, 2020 at 10:34:06AM +0300, Dan Carpenter wrote:  
> > > Assigning "priv->data[-1] = priv->len;" obviously doesn't make sense.
> > > What it does is it ends up corrupting the last byte of priv->len so
> > > priv->len becomes a very high number.
> > > 
> > > Reported-by: syzbot+ed71512d469895b5b34e@syzkaller.appspotmail.com
> > > Fixes: d3ff6ce40031 ("i2c-i801: Enable IRQ for byte_by_byte transactions")
> > > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> > > ---  
> > 
> > Daniel, Jean: what do you think?
> > Also, adding Jarkko to CC who works a lot with this driver...  
> 
> Ping. Adding more people...
> 
> >   
> > > Untested.
> > > 
> > >  drivers/i2c/busses/i2c-i801.c | 1 -
> > >  1 file changed, 1 deletion(-)
> > > 
> > > diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
> > > index f5e69fe56532..420d8025901e 100644
> > > --- a/drivers/i2c/busses/i2c-i801.c
> > > +++ b/drivers/i2c/busses/i2c-i801.c
> > > @@ -584,7 +584,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
> > >  					"SMBus block read size is %d\n",
> > >  					priv->len);
> > >  			}
> > > -			priv->data[-1] = priv->len;
> > >  		}
> > >  
> > >  		/* Read next byte */
> > > -- 
> > > 2.11.0
> > >
Andy Shevchenko March 22, 2020, 9:10 p.m. UTC | #4
On Sun, Mar 22, 2020 at 8:11 PM Jean Delvare <jdelvare@suse.de> wrote:
>
> Hi Wolfram,
>
> Can you please bounce the previous messages in this thread to me? I was
> apparently not Cc'd so I'm missing the context.

You can always take it from patchwork
http://patchwork.ozlabs.org/patch/1222542/
Wolfram Sang March 22, 2020, 9:12 p.m. UTC | #5
> Can you please bounce the previous messages in this thread to me? I was
> apparently not Cc'd so I'm missing the context.

Sure, done. Your email address in the thread was sadly the outdated one.
Jean Delvare March 22, 2020, 10:11 p.m. UTC | #6
Hi Dan,

On Tue, 14 Jan 2020 10:34:06 +0300, Dan Carpenter wrote:
> Assigning "priv->data[-1] = priv->len;" obviously doesn't make sense.
> What it does is it ends up corrupting the last byte of priv->len so
> priv->len becomes a very high number.

I don't follow you, sorry. "priv->data[-1] = priv->len" is writing to
priv->data, not priv->len, so I can't see how this could corrupt
priv->len;

Yes, I see that len is right before data in struct i801_priv, however
priv->data is a pointer, not an array inside the structure, it points
outside the structure so whatever is done through that pointer can't
affect the structure's content.

As for priv->data[-1], in priv->data is defined as:

		priv->data = &data->block[1];

which means the pointer is 1 byte inside the actual block array,
therefore priv->data[-1] albeit convoluted looks legal to me.

> Reported-by: syzbot+ed71512d469895b5b34e@syzkaller.appspotmail.com
> Fixes: d3ff6ce40031 ("i2c-i801: Enable IRQ for byte_by_byte transactions")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
> Untested.
> 
>  drivers/i2c/busses/i2c-i801.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
> index f5e69fe56532..420d8025901e 100644
> --- a/drivers/i2c/busses/i2c-i801.c
> +++ b/drivers/i2c/busses/i2c-i801.c
> @@ -584,7 +584,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
>  					"SMBus block read size is %d\n",
>  					priv->len);
>  			}
> -			priv->data[-1] = priv->len;
>  		}
>  
>  		/* Read next byte */

Definitely not correct. The first byte of the block data array MUST be
the size of the block read. Even if the code above does not do the
right thing, removing the line will not help.

Is it possible that kasan got this wrong due to the convoluted logic?
It's late and I'll check again tomorrow morning but the code looks OK
to me.
Dan Carpenter March 23, 2020, 9:37 a.m. UTC | #7
On Sun, Mar 22, 2020 at 11:11:06PM +0100, Jean Delvare wrote:
> Definitely not correct. The first byte of the block data array MUST be
> the size of the block read. Even if the code above does not do the
> right thing, removing the line will not help.
> 

Yeah.  I misread the code.

> Is it possible that kasan got this wrong due to the convoluted logic?
> It's late and I'll check again tomorrow morning but the code looks OK
> to me.

KASan doesn't work like that.  It works at runtime and doesn't care
about the logic.

https://syzkaller.appspot.com/bug?id=426fc8b1c1b63fb0af524d839dfcf452f2d858e2

At the bottom of the report it shows that we're in a field of f9
poisoned data so it's not priv->len which is wrong.  (My patch was way
off).

mm/kasan/kasan.h:#define KASAN_VMALLOC_INVALID   0xF9  /* unallocated space in vmapped page */

The logic looks okay to me too.  So possibly this was a race condition
or even memory corruption in an unrelated part of the kernel.

regards,
dan carpenter
Jean Delvare March 23, 2020, 5:51 p.m. UTC | #8
On Mon, 23 Mar 2020 12:37:33 +0300, Dan Carpenter wrote:
> On Sun, Mar 22, 2020 at 11:11:06PM +0100, Jean Delvare wrote:
> > Definitely not correct. The first byte of the block data array MUST be
> > the size of the block read. Even if the code above does not do the
> > right thing, removing the line will not help.
> >   
> 
> Yeah.  I misread the code.
> 
> > Is it possible that kasan got this wrong due to the convoluted logic?
> > It's late and I'll check again tomorrow morning but the code looks OK
> > to me.  
> 
> KASan doesn't work like that.  It works at runtime and doesn't care
> about the logic.
> 
> https://syzkaller.appspot.com/bug?id=426fc8b1c1b63fb0af524d839dfcf452f2d858e2
> 
> At the bottom of the report it shows that we're in a field of f9
> poisoned data so it's not priv->len which is wrong.  (My patch was way
> off).
> 
> mm/kasan/kasan.h:#define KASAN_VMALLOC_INVALID   0xF9  /* unallocated space in vmapped page */
> 
> The logic looks okay to me too.  So possibly this was a race condition
> or even memory corruption in an unrelated part of the kernel.

I checked out the exact kernel version this report was generated for,
and the faulty line is:

  592:			priv->data[priv->count++] = inb(SMBBLKDAT(priv));

This would suggest the problem is with priv->count growing beyond the
end of the array, however the fact that we land in a memory spot full
of 0xF9 kind of excludes this possibility (the data before the spot
would contain different data if it was the case).

The other option is that priv->count wasn't initialized at the time
it is used. However I can't see how this could happen, given that the
priv structure is kzalloc'd.

So, to be honest I can't really see how priv->count can get wrong. So
I would be tempted to lend towards the theory that the i2c-i801 driver
was a collateral victim of a memory corruption happening somewhere else
in the kernel. Wouldn't Kasan catch this too? Is it possible to access
the other Kasan reports from the same test run?
diff mbox series

Patch

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index f5e69fe56532..420d8025901e 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -584,7 +584,6 @@  static void i801_isr_byte_done(struct i801_priv *priv)
 					"SMBus block read size is %d\n",
 					priv->len);
 			}
-			priv->data[-1] = priv->len;
 		}
 
 		/* Read next byte */