From ddabd0c70ac807101883b49d951470330ced2bae Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Mon, 21 Aug 2017 19:14:39 -0500 Subject: [PATCH] [libpng16] Added contrib/oss-fuzz directory --- ANNOUNCE | 6 +- CHANGES | 4 + contrib/oss-fuzz/README.txt | 3 + contrib/oss-fuzz/libpng_read_fuzzer.cc | 150 +++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 contrib/oss-fuzz/README.txt create mode 100644 contrib/oss-fuzz/libpng_read_fuzzer.cc diff --git a/ANNOUNCE b/ANNOUNCE index 0a5e3ed7d..e404805ec 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,4 +1,4 @@ -Libpng 1.6.32rc01 - August 18, 2017 +Libpng 1.6.32rc01 - August 22, 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. @@ -104,6 +104,10 @@ Version 1.6.32rc01 [August 18, 2017] names differ only in case; this causes problems with some platforms (github issue #172). +Version 1.6.32rc02 [August 22, 2017] + Added contrib/oss-fuzz directory which contains a target for the oss-fuzz + project. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement diff --git a/CHANGES b/CHANGES index 4cab9aa80..575ef7181 100644 --- a/CHANGES +++ b/CHANGES @@ -5987,6 +5987,10 @@ Version 1.6.32rc01 [August 18, 2017] names differ only in case; this causes problems with some platforms (github issue #172). +Version 1.6.32rc02 [August 22, 2017] + Added contrib/oss-fuzz directory which contains a target for the oss-fuzz + project. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement diff --git a/contrib/oss-fuzz/README.txt b/contrib/oss-fuzz/README.txt new file mode 100644 index 000000000..3e81bb724 --- /dev/null +++ b/contrib/oss-fuzz/README.txt @@ -0,0 +1,3 @@ +Files in this directory are used by the oss-fuzz target for "fuzzing libpng. +They were originally licensed by google inc, using the Apache-2.0 license, +which may be found at https://www.apache.org/licenses/LICENSE-2.0. diff --git a/contrib/oss-fuzz/libpng_read_fuzzer.cc b/contrib/oss-fuzz/libpng_read_fuzzer.cc new file mode 100644 index 000000000..0c9a57104 --- /dev/null +++ b/contrib/oss-fuzz/libpng_read_fuzzer.cc @@ -0,0 +1,150 @@ + +// libpng_read_fuzzer.cc +// Copyright 2017 Glenn Randers-Pehrson +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that could +// previously be found in a LICENSE file. + +// The modifications by Glenn Randers-Pehrson include the addition of a +// PNG_CLEANUP macro and setting the option to ignore ADLER32 checksums. + + +#include +#include +#include + +#include + +#define PNG_INTERNAL +#include "png.h" + +#define PNG_CLEANUP \ + if(png_handler.png_ptr) \ + { \ + if (png_handler.info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + nullptr); \ + else \ + png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \ + } + +struct BufState { + const uint8_t* data; + size_t bytes_left; +}; + +struct PngObjectHandler { + png_infop info_ptr = nullptr; + png_structp png_ptr = nullptr; + png_voidp row_ptr = nullptr; + BufState* buf_state = nullptr; + + ~PngObjectHandler() { + if (row_ptr && png_ptr) { + png_free(png_ptr, row_ptr); + } + if (png_ptr && info_ptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + } + delete buf_state; + } +}; + +void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { + BufState* buf_state = static_cast(png_get_io_ptr(png_ptr)); + if (length > buf_state->bytes_left) { + png_error(png_ptr, "read error"); + } + memcpy(data, buf_state->data, length); + buf_state->bytes_left -= length; + buf_state->data += length; +} + +static const int kPngHeaderSize = 8; + +// Entry point for LibFuzzer. +// Roughly follows the libpng book example: +// http://www.libpng.org/pub/png/book/chapter13.html +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < kPngHeaderSize) { + return 0; + } + + std::vector v(data, data + size); + if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { + // not a PNG. + return 0; + } + + PngObjectHandler png_handler; + png_handler.png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_handler.png_ptr) { + return 0; + } + + png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.info_ptr) { + PNG_CLEANUP + return 0; + } + + png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); +#ifdef PNG_IGNORE_ADLER32 + png_set_option(read_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); +#endif + + // Setting up reading from buffer. + png_handler.buf_state = new BufState(); + png_handler.buf_state->data = data + kPngHeaderSize; + png_handler.buf_state->bytes_left = size - kPngHeaderSize; + png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); + png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); + + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + // Reading. + png_read_info(png_handler.png_ptr, png_handler.info_ptr); + png_handler.row_ptr = png_malloc( + png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, + png_handler.info_ptr)); + + // reset error handler to put png_deleter into scope. + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type; + int filter_type; + + if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, + &height, &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type)) { + PNG_CLEANUP + return 0; + } + + // This is going to be too slow. + if (width && height > 100000000 / width) { + PNG_CLEANUP + return 0; + } + + int passes = png_set_interlace_handling(png_handler.png_ptr); + png_start_read_image(png_handler.png_ptr); + + for (int pass = 0; pass < passes; ++pass) { + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_handler.png_ptr, + static_cast(png_handler.row_ptr), nullptr); + } + } + + PNG_CLEANUP + return 0; +}