From 71a56180e54de5ffa42b7e85835c272771393add Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Tue, 1 Aug 2017 21:42:16 -0500 Subject: [PATCH] [libpng16] Stop memory leak when returning from png_handle_eXIf() with an error (Bug report from the OSS-fuzz project). --- ANNOUNCE | 7 ++++--- CHANGES | 7 ++++--- pnginfo.h | 5 ++++- pngrutil.c | 14 +++++++++++--- pngset.c | 6 +++++- pngtest.c | 32 ++++++++++++++++++++++---------- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE b/ANNOUNCE index 0ec891bbd..9d926a007 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,4 +1,4 @@ -Libpng 1.6.32beta03 - August 1, 2017 +Libpng 1.6.32beta03 - August 2, 2017 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. @@ -39,9 +39,10 @@ Version 1.6.32beta01 [July 31, 2017] Version 1.6.32beta02 [August 1, 2017] Updated contrib/libtests/pngunknown.c with eXIf chunk. -Version 1.6.32beta03 [August 1, 2017] +Version 1.6.32beta03 [August 2, 2017] Initialized btoa[] in pngstest.c - Stop memory leak when returning from png_handle_eXIf() with an error. + Stop memory leak when returning from png_handle_eXIf() with an error + (Bug report from the OSS-fuzz project). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index 174db2c36..fdcc9473a 100644 --- a/CHANGES +++ b/CHANGES @@ -5919,12 +5919,13 @@ Version 1.6.32beta01 [July 31, 2017] png_set_eXIf_1(), respectively, to avoid breaking API compatibility with libpng-1.6.31. -Version 1.6.32beta02 [August 1, 2017] +Version 1.6.32beta02 [August 2, 2017] Updated contrib/libtests/pngunknown.c with eXIf chunk. -Version 1.6.32beta03 [August 1, 2017] +Version 1.6.32beta03 [August 2, 2017] Initialized btoa[] in pngstest.c - Stop memory leak when returning from png_handle_eXIf() with an error. + Stop memory leak when returning from png_handle_eXIf() with an error + (Bug report from the OSS-fuzz project). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/pnginfo.h b/pnginfo.h index 6e6d46a62..d5f6149db 100644 --- a/pnginfo.h +++ b/pnginfo.h @@ -186,8 +186,11 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #endif #ifdef PNG_eXIf_SUPPORTED - int num_exif; + int num_exif; /* Added at libpng-1.6.31 */ png_bytep exif; +# ifdef PNG_READ_eXIf_SUPPORTED + png_bytep eXIf_buf; /* Added at libpng-1.6.32 */ +# endif #endif #ifdef PNG_hIST_SUPPORTED diff --git a/pngrutil.c b/pngrutil.c index 3be7c17cc..7e6ac2077 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -2014,6 +2014,7 @@ void /* PRIVATE */ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int i; + png_bytep eXIf_buf; png_debug(1, "in png_handle_eXIf"); @@ -2031,18 +2032,25 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) eXIf_buf = png_voidcast(png_bytep, png_malloc_warn(png_ptr, length)); + if (eXIf_buf == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + info_ptr->eXIf_buf = eXIf_buf; /* So it will be freed on error */ + info_ptr->free_me |= PNG_FREE_EXIF; for (i = 0; i < length; i++) { png_byte buf[1]; png_crc_read(png_ptr, buf, 1); eXIf_buf[i] = buf[0]; } + info_ptr->eXIf_buf = NULL; if (png_crc_finish(png_ptr, 0) != 0) - { - png_free(png_ptr, eXIf_buf); return; - } png_set_eXIf_1(png_ptr, info_ptr, length, eXIf_buf); diff --git a/pngset.c b/pngset.c index d62ac43b7..55a0e5c91 100644 --- a/pngset.c +++ b/pngset.c @@ -146,7 +146,11 @@ png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr, if (png_ptr == NULL || info_ptr == NULL) return; - png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0); + if (info_ptr->exif) + { + png_free(png_ptr, info_ptr->exif); + info_ptr->exif = NULL; + } info_ptr->num_exif = num_exif; diff --git a/pngtest.c b/pngtest.c index 3b7bc67b3..7513a8fae 100644 --- a/pngtest.c +++ b/pngtest.c @@ -936,8 +936,12 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_free(read_ptr, row_buf); row_buf = NULL; + if (verbose != 0) + fprintf(STDERR, " destroy read structs\n"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); #ifdef PNG_WRITE_SUPPORTED + if (verbose != 0) + fprintf(STDERR, " destroy write structs\n"); png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif @@ -952,11 +956,13 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) if (setjmp(png_jmpbuf(write_ptr))) { fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + if (verbose != 0) + fprintf(STDERR, " destroying read structs\n"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + if (verbose != 0) + fprintf(STDERR, " destroying write structs\n"); png_destroy_info_struct(write_ptr, &write_end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif FCLOSE(fpin); FCLOSE(fpout); return (1); @@ -1192,16 +1198,19 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) } } #endif -#ifdef PNG_eXIf_SUPPORTED +#ifdef PNG_READ_eXIf_SUPPORTED { - png_bytep exif; + png_bytep exif=NULL; png_uint_32 exif_length; if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0) { - printf(" eXIf type %c%c, %d bytes\n",exif[0],exif[1], - (int)exif_length); + if (exif_length > 1) + printf(" eXIf type %c%c, %d bytes\n",exif[0],exif[1], + (int)exif_length); +# ifdef PNG_WRITE_eXIf_SUPPORTED png_set_eXIf_1(write_ptr, write_info_ptr, exif_length, exif); +# endif } } #endif @@ -1547,16 +1556,19 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) } } #endif -#ifdef PNG_eXIf_SUPPORTED +#ifdef PNG_READ_eXIf_SUPPORTED { - png_bytep exif; + png_bytep exif=NULL; png_uint_32 exif_length; if (png_get_eXIf_1(read_ptr, end_info_ptr, &exif_length, &exif) != 0) { - printf(" eXIf type %c%c, %d bytes\n",exif[0],exif[1], - (int)exif_length); + if (exif_length > 1) + printf(" eXIf type %c%c, %d bytes\n",exif[0],exif[1], + (int)exif_length); +# ifdef PNG_WRITE_eXIf_SUPPORTED png_set_eXIf_1(write_ptr, write_end_info_ptr, exif_length, exif); +# endif } } #endif