diff --git a/ANNOUNCE b/ANNOUNCE index faa5c1f8e..53e0108fd 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -515,6 +515,11 @@ Version 1.7.0beta31 [February 5, 2014] outside the range that should be produced by the shift. Reversing the order on read makes the two transforms work together correctly and mirrors the order used on write. + Do not read invalid sBIT chunks. Previously libpng only checked sBIT + values on write, so a malicious PNG writer could therefore cause + the read code to return an invalid sBIT chunk, which might lead to + application errors or crashes. Such chunks are now skipped (with + chunk_benign_error). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index bb47f5526..a88a93b90 100644 --- a/CHANGES +++ b/CHANGES @@ -4804,6 +4804,11 @@ Version 1.7.0beta31 [February 5, 2014] outside the range that should be produced by the shift. Reversing the order on read makes the two transforms work together correctly and mirrors the order used on write. + Do not read invalid sBIT chunks. Previously libpng only checked sBIT + values on write, so a malicious PNG writer could therefore cause + the read code to return an invalid sBIT chunk, which might lead to + application errors or crashes. Such chunks are now skipped (with + chunk_benign_error). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/pngrutil.c b/pngrutil.c index cb0a9e386..60ed29e0c 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1091,13 +1091,12 @@ png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) void /* PRIVATE */ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - unsigned int truelen; + unsigned int truelen, i; + png_byte sample_depth; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); - buf[0] = buf[1] = buf[2] = buf[3] = 0; - if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_chunk_error(png_ptr, "missing IHDR"); @@ -1116,10 +1115,16 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { truelen = 3; + sample_depth = 8; + } else + { truelen = png_ptr->channels; + sample_depth = png_ptr->bit_depth; + } if (length != truelen || length > 4) { @@ -1128,11 +1133,19 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) return; } + buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; png_crc_read(png_ptr, buf, truelen); if (png_crc_finish(png_ptr, 0)) return; + for (i=0; i sample_depth) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) { png_ptr->sig_bit.red = buf[0];