[libpng16] Reject oversized iCCP profile length

The code now validates the ICC profile length against the user chunk limit
before the buffer is allocated, as opposed to doing it while the buffer is read.

This removes the potential to consume virtual address space with a carefully
crafted ICC profile; only an issue on 32-bit systems where a valid profile can
be up to 2^32-4 bytes in length.  libpng never writes beyond the application
supplied limit, but previously it did allocate a buffer of the size specified in
the profile header.  The exploitability of this is almost zero; the address
space is released as soon as the PNG read completes.

Also clean up PNG_DEBUG compile of pngtest.c.

Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
John Bowler
2016-08-10 15:35:09 -07:00
parent cdc0e74ee6
commit 92a7c79db2
5 changed files with 85 additions and 38 deletions

40
png.c
View File

@@ -1931,8 +1931,8 @@ png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
static const png_byte D50_nCIEXYZ[12] =
{ 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d };
int /* PRIVATE */
png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
static int /* bool */
icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
png_const_charp name, png_uint_32 profile_length)
{
if (profile_length < 132)
@@ -1942,6 +1942,40 @@ png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
return 1;
}
#ifdef PNG_READ_iCCP_SUPPORTED
int /* PRIVATE */
png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
png_const_charp name, png_uint_32 profile_length)
{
if (!icc_check_length(png_ptr, colorspace, name, profile_length))
return 0;
/* This needs to be here because the 'normal' check is in
* png_decompress_chunk, yet this happens after the attempt to
* png_malloc_base the required data. We only need this on read; on write
* the caller supplies the profile buffer so libpng doesn't allocate it. See
* the call to icc_check_length below (the write case).
*/
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
else if (png_ptr->user_chunk_malloc_max > 0 &&
png_ptr->user_chunk_malloc_max < profile_length)
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"exceeds application limits");
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"exceeds libpng limits");
# else /* !SET_USER_LIMITS */
/* This will get compiled out on all 32-bit and better systems. */
else if (PNG_SIZE_MAX < profile_length)
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"exceeds system limits");
# endif /* !SET_USER_LIMITS */
return 1;
}
#endif /* READ_iCCP */
int /* PRIVATE */
png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
png_const_charp name, png_uint_32 profile_length,
@@ -2377,7 +2411,7 @@ png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,
if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
return 0;
if (png_icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&
if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&
png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
color_type) != 0 &&
png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,