From 9f7d5aa973a9bddd405084b4a7be4c4b5fd1503b Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Sun, 1 Nov 2015 13:01:56 -0600 Subject: [PATCH] [libpng17] Prevent setting or writing over-length PLTE chunk (Cosmin Truta). Silently truncate over-length PLTE chunk while reading. --- ANNOUNCE | 6 ++++-- CHANGES | 7 +++++-- pngrutil.c | 16 ++++++++++++++-- pngset.c | 23 ++++++++++++++--------- pngwutil.c | 7 +++++-- 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/ANNOUNCE b/ANNOUNCE index 01923f32e..366e90dfe 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ -Libpng 1.7.0beta67 - October 10, 2015 +Libpng 1.7.0beta67 - November 1, 2015 This is not intended to be a public release. It will be replaced within a few weeks by a public version or by another test version. @@ -944,13 +944,15 @@ Version 1.7.0beta66 [October 2, 2015] extended sBIT handling to the colormap code in the simplified API which is separately implemented in pngread.c (John Bowler). -Version 1.7.0beta67 [October 10, 2015] +Version 1.7.0beta67 [November 1, 2015] Fixed 'pow' macros in pngvalid.c. It is legal for 'pow' to be a macro, therefore the argument list cannot contain preprocessing directives. Make sure pow is a function where this happens. This is a minimal safe fix, the issue only arises in non-performance-critical code (bug report by Curtis Leach, fix by John Bowler). Added sPLT chunk support to pngtest.c + Prevent setting or writing over-length PLTE chunk (Cosmin Truta). + Silently truncate over-length PLTE chunk while reading. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index ee43ab2f9..88765fe55 100644 --- a/CHANGES +++ b/CHANGES @@ -3754,7 +3754,8 @@ Version 1.5.7beta04 [November 17, 2011] Version 1.5.7beta05 [November 25, 2011] Removed "zTXt" from warning in generic chunk decompression function. Validate time settings passed to pngset() and png_convert_to_rfc1123() - (Frank Busse). + (Frank Busse). Note: This prevented CVE-2015-7981 from affecting + libpng-1.5.7 and later. Added MINGW support to CMakeLists.txt Reject invalid compression flag or method when reading the iTXt chunk. Backed out 'simplified' API changes. The API seems too complex and there @@ -5243,13 +5244,15 @@ Version 1.7.0beta66 [October 2, 2015] extended sBIT handling to the colormap code in the simplified API which is separately implemented in pngread.c (John Bowler). -Version 1.7.0beta67 [October 10, 2015] +Version 1.7.0beta67 [November 1, 2015] Fixed 'pow' macros in pngvalid.c. It is legal for 'pow' to be a macro, therefore the argument list cannot contain preprocessing directives. Make sure pow is a function where this happens. This is a minimal safe fix, the issue only arises in non-performance-critical code (bug report by Curtis Leach, fix by John Bowler). Added sPLT chunk support to pngtest.c + Prevent setting or writing over-length PLTE chunk (Cosmin Truta). + Silently truncate over-length PLTE chunk while reading. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/pngrutil.c b/pngrutil.c index 1063db319..c8db63902 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -849,7 +849,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr) { png_color palette[PNG_MAX_PALETTE_LENGTH]; png_uint_32 length = png_ptr->chunk_length; - int num, i; + int max_palette_length, num, i; png_colorp pal_ptr; png_debug(1, "in png_handle_PLTE"); @@ -868,6 +868,10 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr) } #endif + max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) { png_crc_finish(png_ptr, length); @@ -878,7 +882,15 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr) } /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ - num = (int)/*SAFE*/length / 3; + num = (int)length / 3; + + /* If the palette has 256 or fewer entries but is too large for the bit + * depth, we don't issue an error, to preserve the behavior of previous + * libpng versions. We silently truncate the unused extra palette entries + * here. + */ + if (num > max_palette_length) + num = max_palette_length; for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) { diff --git a/pngset.c b/pngset.c index 16549b03d..5e2656ad6 100644 --- a/pngset.c +++ b/pngset.c @@ -124,12 +124,12 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, png_fixed(png_ptr, red_X, "cHRM Red X"), png_fixed(png_ptr, red_Y, "cHRM Red Y"), png_fixed(png_ptr, red_Z, "cHRM Red Z"), - png_fixed(png_ptr, green_X, "cHRM Red X"), - png_fixed(png_ptr, green_Y, "cHRM Red Y"), - png_fixed(png_ptr, green_Z, "cHRM Red Z"), - png_fixed(png_ptr, blue_X, "cHRM Red X"), - png_fixed(png_ptr, blue_Y, "cHRM Red Y"), - png_fixed(png_ptr, blue_Z, "cHRM Red Z")); + png_fixed(png_ptr, green_X, "cHRM Green X"), + png_fixed(png_ptr, green_Y, "cHRM Green Y"), + png_fixed(png_ptr, green_Z, "cHRM Green Z"), + png_fixed(png_ptr, blue_X, "cHRM Blue X"), + png_fixed(png_ptr, blue_Y, "cHRM Blue Y"), + png_fixed(png_ptr, blue_Z, "cHRM Blue Z")); } # endif /* FLOATING_POINT */ @@ -502,12 +502,17 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette) { + png_uint_32 max_palette_length; + png_debug1(1, "in %s storage function", "PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; - if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) + max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + if (num_palette < 0 || num_palette > (int) max_palette_length) { if ((info_ptr->format == PNG_FORMAT_FLAG_COLORMAP) != 0) png_chunk_error(png_ptr, "Invalid palette length"); @@ -537,8 +542,8 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead - * of num_palette entries, in case of an invalid PNG file that has - * too-large sample values. + * of num_palette entries, in case of an invalid PNG file or incorrect + * call to png_set_PLTE() with too-large sample values. */ png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); diff --git a/pngwutil.c b/pngwutil.c index 8ab7e334c..f9bfe28ba 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -911,17 +911,20 @@ void /* PRIVATE */ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, unsigned int num_pal) { - png_uint_32 i; + png_uint_32 max_palette_length, i; png_const_colorp pal_ptr; png_byte buf[3]; png_debug(1, "in png_write_PLTE"); + max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + if (( # ifdef PNG_MNG_FEATURES_SUPPORTED (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && # endif /* MNG_FEATURES */ - num_pal == 0) || num_pal > PNG_MAX_PALETTE_LENGTH) + num_pal == 0) || num_pal > max_palette_length) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {