[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 22/22] libxc: check blob size before proceeding in xc_dom_check_gzip



Andrew Cooper writes ("Re: [PATCH 22/22] libxc: check blob size before 
proceeding in xc_dom_check_gzip"):
> On 07/06/13 19:27, Ian Jackson wrote:
> > +    if ( ziplen < 6 )
> > +        /* too small */
> > +        return 0;
> > +
> >      if ( strncmp(blob, "\037\213", 2) )
> >          /* not gzipped */
> >          return 0;
> 
> The above change is certainly good and correct.
> 
> Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

Thanks.  I'll leave off your Reviewed-by in my copy of the series
until we've resolved these comments.

> I do however have concerns about the rest of the function, immediately
> after the context.  I spot any other specific security related issues,
> but would appreciate comments/thoughts as to whether these should be
> part of this patch or part of a subsequent set of bugfix patches.

I think it would be best to do all needed fixes to xc_dom_check_gzip
(and perhaps related functions) in one patch, if they're not intricate.

> >     gzlen = blob + ziplen - 4;
> 
> Arithmatic on a void pointer (blob), and a possibility to overflow,
> although this seems unlikely given that it would have to pass
> xc_dom_malloc_filemap() in the first place.  There is a GNU extention
> which allows this line to Do The Right Thing, despite violating the C spec.

This code already relies on the GNU extension to do arithmetic on a
void pointer.  This is defined to do the same thing as arithmetic on a
char*, and is safe under the same conditions as the char* arithmetic.

In this case (it's left associative) this expression computes
   (blob + ziplen) - 4
Now, blob + ziplen is safe because that's the input image size.  Ie,
it's a pointer to the end of the image, which one is permitted to
compute.

Since ziplen >= 6 (because of the earlier test) it is then safe to
retreat by 4 bytes.
   
> >     unziplen = gzlen[3] << 24 | gzlen[2] << 16 | gzlen[1] << 8 | gzlen[0];
> >     if ( (unziplen < 0) || (unziplen > XC_DOM_DECOMPRESS_MAX) )
> 
> unziplen is unsigned, so (unziplen < 0) is necessarily false.

Yes, but I don't intend to change this, obviously.

> >     {
> >          xc_dom_printf
> >             (xch,
> >              "%s: size (zip %zd, unzip %zd) looks insane, skip gunzip",
> >              __FUNCTION__, ziplen, unziplen);
> 
> ziplen and unziplen are both unsigned, so the format string should be
> %zu instead.

xc_dom_printf uses stdarg to get the arguments.  Given %zd it will use
va_arg(,int).  The requirement for va_arg is that the actual promoted
argument type and the specified type are "compatible" (C99 7.15.1.1
para 2).  `int' and `unsigned' are indeed not compatible.  So this has
undefined behaviour.

However I do not propose to try to audit our entire codebase for calls
to print a signed integer with %x (which has, technically, undefined
behaviour if the value is negative).  Instead, I propose that we
declare that we require of the C implementation that it tolerate use
of va_arg where the actual and supplied types are not compatible but
do pass the strict aliasing rules.

As a justification for this I observe that gcc's format string warning
system tolerates passing wrong-signedness arguments to printf %d etc.

> While XC_DOM_DECOMPRESS_MAX is set to a default of 1GB, if it is
> changes, unziplen + 16 can overflow.

This should be dealt with by a comment near its definition.  TBH IMO
if anyone defines it to >= nearly 4G  they deserve to lose.

Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.