lkml.org 
[lkml]   [2019]   [Apr]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: KASAN: slab-out-of-bounds Read in hex_string
On Mon, 29 Apr 2019, Eric Biggers wrote:

> On Mon, Apr 29, 2019 at 04:07:04PM -0400, Alan Stern wrote:

> > Accessing beyond the end of the descriptor.
> >
> > #syz test: https://github.com/google/kasan.git usb-fuzzer
> >
> > --- a/drivers/video/fbdev/udlfb.c
> > +++ b/drivers/video/fbdev/udlfb.c
> > @@ -1511,6 +1511,7 @@ static int dlfb_parse_vendor_descriptor(
> > char *buf;
> > char *desc_end;
> > int total_len;
> > + int width;
> >
> > buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
> > if (!buf)
> > @@ -1529,9 +1530,10 @@ static int dlfb_parse_vendor_descriptor(
> > }
> >
> > if (total_len > 5) {
> > + width = min(total_len, 11);
> > dev_info(&intf->dev,
> > - "vendor descriptor length: %d data: %11ph\n",
> > - total_len, desc);
> > + "vendor descriptor length: %d data: %*ph\n",
> > + total_len, width, desc);
> >
> > if ((desc[0] != total_len) || /* descriptor length */
> > (desc[1] != 0x5f) || /* vendor descriptor type */
> >
> >
>
> Why not write just:
>
> dev_info(&intf->dev,
> "vendor descriptor length: %d data: %*ph\n",
> total_len, min(total_len, 11), desc);

I did consider doing that. In the end I decided adding an extra
temporary variable made the code a little more readable. (For some
reason, extra recursion -- a function call embedded in a function
argument -- seems to demand more mental effort than an extra
temporary. Maybe my brain is just getting old...)

> Also, aren't there more out-of-bounds reads in the code just after? It only
> checks for at least 1 byte available, but then it reads up to 7 bytes:
>
> while (desc < desc_end) {
> u8 length;
> u16 key;
>
> key = *desc++;
> key |= (u16)*desc++ << 8;
> length = *desc++;
>
> switch (key) {
> case 0x0200: { /* max_area */
> u32 max_area = *desc++;
> max_area |= (u32)*desc++ << 8;
> max_area |= (u32)*desc++ << 16;
> max_area |= (u32)*desc++ << 24;
> dev_warn(&intf->dev,
> "DL chip limited to %d pixel modes\n",
> max_area);
> dlfb->sku_pixel_limit = max_area;
> break;
> }
> default:
> break;
> }
> desc += length;
> }

Quite right. Please feel free to submit a patch fixing all these
problems.

> Also I couldn't help but notice it's also using 'char' rather than 'u8',
> so bytes >= 0x80 are read incorrectly as they're sign extended...

As I recall, the C standard doesn't specify whether char is signed or
unsigned; it can vary with the implementation. However you are
certainly correct that to ensure there is no sign extension, the code
should use unsigned char or u8.

Alan Stern

\
 
 \ /
  Last update: 2019-04-30 16:14    [W:0.081 / U:0.176 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site