1 2// libpng_read_fuzzer.cc 3// Copyright 2017 Glenn Randers-Pehrson 4// Copyright 2015 The Chromium Authors. All rights reserved. 5// Use of this source code is governed by a BSD-style license that may 6// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE 7 8// Last changed in libpng 1.6.33beta03 [September 27, 2017] 9 10// The modifications in 2017 by Glenn Randers-Pehrson include 11// 1. addition of a PNG_CLEANUP macro, 12// 2. setting the option to ignore ADLER32 checksums, 13// 3. adding "#include <string.h>" which is needed on some platforms 14// to provide memcpy(). 15// 4. adding read_end_info() and creating an end_info structure. 16 17#include <stddef.h> 18#include <stdint.h> 19#include <string.h> 20 21#include <vector> 22 23#define PNG_INTERNAL 24#include "png.h" 25 26struct BufState { 27 const uint8_t* data; 28 size_t bytes_left; 29}; 30 31struct PngObjectHandler { 32 png_infop info_ptr = nullptr; 33 png_structp png_ptr = nullptr; 34 png_infop end_info_ptr = nullptr; 35 png_voidp row_ptr = nullptr; 36 BufState* buf_state = nullptr; 37 38 ~PngObjectHandler() { 39 if (row_ptr) 40 png_free(png_ptr, row_ptr); 41 if (end_info_ptr) 42 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); 43 else if (info_ptr) 44 png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); 45 else 46 png_destroy_read_struct(&png_ptr, nullptr, nullptr); 47 delete buf_state; 48 } 49}; 50 51void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { 52 BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr)); 53 if (length > buf_state->bytes_left) { 54 png_error(png_ptr, "read error"); 55 } 56 memcpy(data, buf_state->data, length); 57 buf_state->bytes_left -= length; 58 buf_state->data += length; 59} 60 61static const int kPngHeaderSize = 8; 62 63// Entry point for LibFuzzer. 64// Roughly follows the libpng book example: 65// http://www.libpng.org/pub/png/book/chapter13.html 66 67extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { 68 if (size < kPngHeaderSize) { 69 return 0; 70 } 71 72 std::vector<unsigned char> v(data, data + size); 73 if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { 74 // not a PNG. 75 return 0; 76 } 77 78 PngObjectHandler png_handler; 79 png_handler.png_ptr = nullptr; 80 png_handler.row_ptr = nullptr; 81 png_handler.info_ptr = nullptr; 82 png_handler.end_info_ptr = nullptr; 83 84 png_handler.png_ptr = png_create_read_struct 85 (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 86 if (!png_handler.png_ptr) { 87 return 0; 88 } 89 90#define PNG_CLEANUP \ 91 if(png_handler.png_ptr) \ 92 { \ 93 if (png_handler.row_ptr) \ 94 png_free(png_handler.png_ptr, png_handler.row_ptr); \ 95 if (png_handler.end_info_ptr) \ 96 png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ 97 &png_handler.end_info_ptr); \ 98 else if (png_handler.info_ptr) \ 99 png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ 100 nullptr); \ 101 else \ 102 png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \ 103 png_handler.png_ptr = nullptr; \ 104 png_handler.row_ptr = nullptr; \ 105 png_handler.info_ptr = nullptr; \ 106 png_handler.end_info_ptr = nullptr; \ 107 } 108 109 png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); 110 if (!png_handler.info_ptr) { 111 PNG_CLEANUP 112 return 0; 113 } 114 115 png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); 116 if (!png_handler.end_info_ptr) { 117 PNG_CLEANUP 118 return 0; 119 } 120 121 /* Treat benign errors as warnings */ 122 png_set_benign_errors(png_handler.png_ptr, 1); 123 124 png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); 125 126#ifdef PNG_IGNORE_ADLER32 127 png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); 128#endif 129 130 // Setting up reading from buffer. 131 png_handler.buf_state = new BufState(); 132 png_handler.buf_state->data = data + kPngHeaderSize; 133 png_handler.buf_state->bytes_left = size - kPngHeaderSize; 134 png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); 135 png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); 136 137 if (setjmp(png_jmpbuf(png_handler.png_ptr))) { 138 PNG_CLEANUP 139 return 0; 140 } 141 142 // Reading. 143 png_read_info(png_handler.png_ptr, png_handler.info_ptr); 144 png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); 145 png_handler.row_ptr = png_malloc( 146 png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, 147 png_handler.info_ptr)); 148 149 // reset error handler to put png_deleter into scope. 150 if (setjmp(png_jmpbuf(png_handler.png_ptr))) { 151 PNG_CLEANUP 152 return 0; 153 } 154 155 png_uint_32 width, height; 156 int bit_depth, color_type, interlace_type, compression_type; 157 int filter_type; 158 159 if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, 160 &height, &bit_depth, &color_type, &interlace_type, 161 &compression_type, &filter_type)) { 162 PNG_CLEANUP 163 return 0; 164 } 165 166 // This is going to be too slow. 167 if (width && height > 100000000 / width) { 168 PNG_CLEANUP 169 return 0; 170 } 171 172 int passes = png_set_interlace_handling(png_handler.png_ptr); 173 png_start_read_image(png_handler.png_ptr); 174 175 /* To do: prevent the optimizer from removing this code entirely */ 176 for (int pass = 0; pass < passes; ++pass) { 177 for (png_uint_32 y = 0; y < height; ++y) { 178 png_read_row(png_handler.png_ptr, 179 static_cast<png_bytep>(png_handler.row_ptr), nullptr); 180 } 181 } 182 183 png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); 184 185 PNG_CLEANUP 186 187 /* TO do: exercise the progressive reader here */ 188 189 return 0; 190} 191