• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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