From fd97f3e31e590c6e74a59d2d63e21749bd2f142e Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Sat, 31 Oct 2015 07:56:39 -0500 Subject: [PATCH] [libpng14] Prevent writing over-length PLTE chunk (Cosmin Truta) and silently truncate over-length PLTE chunk while reading. --- libpng.3 | 5 +++++ pngrutil.c | 13 ++++++++++++- pngset.c | 13 +++++++++---- pngwutil.c | 7 +++++-- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/libpng.3 b/libpng.3 index a2da89aeb..b6bcaea5b 100644 --- a/libpng.3 +++ b/libpng.3 @@ -3586,6 +3586,11 @@ PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS. We removed the trailing '.' from the warning and error messages. +Starting with libpng-1.4.17, attempting to set an over-length PLTE chunk +is an error. Previously this requirement of the PNG specification was not +enforced, and the palette was always limited to 256 entries. An over-length +PLTE chunk found in an input PNG is silently truncated. + .SH X. Detecting libpng The png_get_io_ptr() function has been present since libpng-0.88, has never diff --git a/pngrutil.c b/pngrutil.c index 25b8b88a3..fd561f86d 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -551,7 +551,7 @@ void /* PRIVATE */ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_color palette[PNG_MAX_PALETTE_LENGTH]; - int num, i; + int max_palette_length, num, i; #ifdef PNG_POINTER_INDEXING_SUPPORTED png_colorp pal_ptr; #endif @@ -603,8 +603,19 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } } + max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ 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; + #ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) { diff --git a/pngset.c b/pngset.c index 39e7b3c43..fb35dd3fa 100644 --- a/pngset.c +++ b/pngset.c @@ -1,7 +1,7 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.4.17 [October 28, 2015] + * Last changed in libpng 1.4.17 [October 31, 2015] * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -427,12 +427,17 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, png_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->color_type == PNG_COLOR_TYPE_PALETTE) png_error(png_ptr, "Invalid palette length"); @@ -450,8 +455,8 @@ png_set_PLTE(png_structp png_ptr, png_infop 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_colorp)png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); diff --git a/pngwutil.c b/pngwutil.c index 525485b13..3ad6ae3a4 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -601,17 +601,20 @@ void /* PRIVATE */ png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) { PNG_PLTE; - png_uint_32 i; + png_uint_32 max_palette_length, i; png_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) && #endif - num_pal == 0) || num_pal > 256) + num_pal == 0) || num_pal > max_palette_length) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {