diff options
author | John Bowler <jbowler@acm.org> | 2013-01-10 11:01:00 -0600 |
---|---|---|
committer | Glenn Randers-Pehrson <glennrp at users.sourceforge.net> | 2013-01-10 11:01:00 -0600 |
commit | 4accd423c283f95fbd6672c2baa4df034a8afdef (patch) | |
tree | a1de4a42b9578f0dfae1a58ea4fa67d40bbd00fd | |
parent | f62caaf4dcff59ac2090274f56ab91c804a9525a (diff) | |
download | libpng-4accd423c283f95fbd6672c2baa4df034a8afdef.tar.gz |
[libpng17]Fixed conceivable but difficult to repro overflow. Also added
two test programs to generate and test a PNG which should have the problem.
-rw-r--r-- | ANNOUNCE | 7 | ||||
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | contrib/libtests/fakepng.c | 57 | ||||
-rw-r--r-- | contrib/libtests/readpng.c | 104 | ||||
-rw-r--r-- | pnginfo.h | 5 | ||||
-rw-r--r-- | pngset.c | 28 |
6 files changed, 194 insertions, 11 deletions
@@ -1,5 +1,5 @@ -Libpng 1.7.0alpha07 - January 1, 2013 +Libpng 1.7.0alpha07 - January 10, 2013 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. @@ -11,7 +11,6 @@ Source files with LF line endings (for Unix/Linux) and with a 1.7.0alpha07.tar.xz (LZMA-compressed, recommended) 1.7.0alpha07.tar.gz - 1.7.0alpha07.tar.bz2 Source files with CRLF line endings (for Windows), without the "configure" script @@ -107,7 +106,9 @@ Version 1.7.0alpha05 [December 24, 2012] Version 1.7.0alpha06 [January 1, 2013] Fixed 'make distcheck' on SUN OS - libpng.so was not being removed -Version 1.7.0alpha07 [January 1, 2013] +Version 1.7.0alpha07 [January 10, 2013] + Fixed conceivable but difficult to repro overflow. Also added two test + programs to generate and test a PNG which should have the problem. =========================================================================== NOTICE November 17, 2012: @@ -4392,7 +4392,9 @@ Version 1.7.0alpha05 [December 24, 2012] Version 1.7.0alpha06 [January 1, 2013] Fixed 'make distcheck' on SUN OS - libpng.so was not being removed -Version 1.7.0alpha07 [January 1, 2013] +Version 1.7.0alpha07 [January 10, 2013] + Fixed conceivable but difficult to repro overflow. Also added two test + programs to generate and test a PNG which should have the problem. =========================================================================== NOTICE November 17, 2012: diff --git a/contrib/libtests/fakepng.c b/contrib/libtests/fakepng.c new file mode 100644 index 000000000..ba360d15a --- /dev/null +++ b/contrib/libtests/fakepng.c @@ -0,0 +1,57 @@ +/* Fake a PNG - just write it out directly. */ +#include <stdio.h> +#include <zlib.h> /* for crc32 */ + +void +put_uLong(uLong val) +{ + putchar(val >> 24); + putchar(val >> 16); + putchar(val >> 8); + putchar(val >> 0); +} + +void +put_chunk(const unsigned char *chunk, uInt length) +{ + uLong crc; + + put_uLong(length-4); /* Exclude the tag */ + + fwrite(chunk, length, 1, stdout); + + crc = crc32(0, Z_NULL, 0); + put_uLong(crc32(crc, chunk, length)); +} + +const unsigned char signature[] = +{ + 137, 80, 78, 71, 13, 10, 26, 10 +}; + +const unsigned char IHDR[] = +{ + 73, 72, 68, 82, /* IHDR */ + 0, 0, 0, 1, /* width */ + 0, 0, 0, 1, /* height */ + 1, /* bit depth */ + 0, /* color type: greyscale */ + 0, /* compression method */ + 0, /* filter method */ + 0 /* interlace method: none */ +}; + +const unsigned char unknown[] = +{ + 'u', 'n', 'K', 'n' /* "unKn" - private safe to copy */ +}; + +int +main(void) +{ + fwrite(signature, sizeof signature, 1, stdout); + put_chunk(IHDR, sizeof IHDR); + + for(;;) + put_chunk(unknown, sizeof unknown); +} diff --git a/contrib/libtests/readpng.c b/contrib/libtests/readpng.c new file mode 100644 index 000000000..631325766 --- /dev/null +++ b/contrib/libtests/readpng.c @@ -0,0 +1,104 @@ +/* readpng.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Load an arbitrary number of PNG files (from the command line, or, if there + * are no arguments on the command line, from stdin) then run a time test by + * reading each file by row. The test does nothing with the read result and + * does no transforms. The only output is a time as a floating point number of + * seconds with 9 decimal digits. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#if (defined HAVE_CONFIG_H) && !(defined PNG_NO_CONFIG_H) +# include <config.h> +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include <png.h> +#else +# include "../../png.h" +#endif + +static int +read_png(FILE *fp) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + png_infop info_ptr = NULL; + png_bytep row = NULL, display = NULL; + + if (png_ptr == NULL) + return 0; + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (row != NULL) free(row); + if (display != NULL) free(display); + return 0; + } + + png_init_io(png_ptr, fp); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); + + png_read_info(png_ptr, info_ptr); + + { + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + row = malloc(rowbytes); + display = malloc(rowbytes); + + if (row == NULL || display == NULL) + png_error(png_ptr, "OOM allocating row buffers"); + + { + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int passes = png_set_interlace_handling(png_ptr); + int pass; + + png_start_read_image(png_ptr); + + for (pass = 0; pass < passes; ++pass) + { + png_uint_32 y = height; + + /* NOTE: this trashes the row each time; interlace handling won't + * work, but this avoids memory thrashing for speed testing. + */ + while (y-- > 0) + png_read_row(png_ptr, row, display); + } + } + } + + /* Make sure to read to the end of the file: */ + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + free(row); + free(display); + return 1; +} + +int +main(void) +{ + /* Exit code 0 on success. */ + return !read_png(stdin); +} @@ -223,7 +223,10 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED /* Storage for unknown chunks that the library doesn't recognize. */ png_unknown_chunkp unknown_chunks; - unsigned int unknown_chunks_num; + /* The type of this field must match png_struct::user_chunk_cache_max, + * else overflow can occur. + */ + png_uint_32 unknown_chunks_num; #endif #ifdef PNG_sPLT_SUPPORTED @@ -1125,11 +1125,12 @@ check_location(png_const_structrp png_ptr, int location) void PNGAPI png_set_unknown_chunks(png_const_structrp png_ptr, - png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns_in) { + png_uint_32 num_unknowns; png_unknown_chunkp np; - if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0) + if (png_ptr == NULL || info_ptr == NULL || num_unknowns_in <= 0) return; /* Check for the failure cases where support has been disabled at compile @@ -1160,9 +1161,24 @@ png_set_unknown_chunks(png_const_structrp png_ptr, * undefined behavior. Changing to png_malloc fixes this by producing a * png_error. The (png_size_t) cast was also removed as it hides a potential * overflow. - * - * TODO: fix the potential overflow in the multiply */ + num_unknowns = (unsigned int)/*SAFE*/num_unknowns_in; + + /* There are two overflow conditions, one on the count one on memory, on a + * 32-bit system the memory limit is critical, on a 64-bit system the count + * limit. + */ + if (num_unknowns > PNG_UINT_32_MAX - info_ptr->unknown_chunks_num || + num_unknowns > PNG_SIZE_MAX/(sizeof *np) - info_ptr->unknown_chunks_num) + { + /* This is a benign read error (user limits are disabled and we are about + * to overflow 2^32 chunks) and an application write error. + */ + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); + return; + } + np = png_voidcast(png_unknown_chunkp, png_malloc(png_ptr, (info_ptr->unknown_chunks_num + (unsigned int)num_unknowns) * (sizeof (png_unknown_chunk)))); @@ -1179,8 +1195,8 @@ png_set_unknown_chunks(png_const_structrp png_ptr, /* Increment unknown_chunks_num each time round the loop to protect the * just-allocated chunk data. */ - for (; --num_unknowns >= 0; - ++np, ++unknowns, ++(info_ptr->unknown_chunks_num)) + for (; num_unknowns > 0; + --num_unknowns, ++np, ++unknowns, ++(info_ptr->unknown_chunks_num)) { memcpy(np->name, unknowns->name, (sizeof unknowns->name)); np->name[(sizeof np->name)-1] = '\0'; |