1 |
|
---|
2 | // libpng_read_fuzzer.cc
|
---|
3 | // Copyright 2017-2018 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.35 [July 15, 2018]
|
---|
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 | // 5. adding calls to png_set_*() transforms commonly used by browsers.
|
---|
17 |
|
---|
18 | #include <stddef.h>
|
---|
19 | #include <stdint.h>
|
---|
20 | #include <string.h>
|
---|
21 |
|
---|
22 | #include <vector>
|
---|
23 |
|
---|
24 | #define PNG_INTERNAL
|
---|
25 | #include "png.h"
|
---|
26 |
|
---|
27 | #define PNG_CLEANUP \
|
---|
28 | if(png_handler.png_ptr) \
|
---|
29 | { \
|
---|
30 | if (png_handler.row_ptr) \
|
---|
31 | png_free(png_handler.png_ptr, png_handler.row_ptr); \
|
---|
32 | if (png_handler.end_info_ptr) \
|
---|
33 | png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
|
---|
34 | &png_handler.end_info_ptr); \
|
---|
35 | else if (png_handler.info_ptr) \
|
---|
36 | png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
|
---|
37 | nullptr); \
|
---|
38 | else \
|
---|
39 | png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \
|
---|
40 | png_handler.png_ptr = nullptr; \
|
---|
41 | png_handler.row_ptr = nullptr; \
|
---|
42 | png_handler.info_ptr = nullptr; \
|
---|
43 | png_handler.end_info_ptr = nullptr; \
|
---|
44 | }
|
---|
45 |
|
---|
46 | struct BufState {
|
---|
47 | const uint8_t* data;
|
---|
48 | size_t bytes_left;
|
---|
49 | };
|
---|
50 |
|
---|
51 | struct PngObjectHandler {
|
---|
52 | png_infop info_ptr = nullptr;
|
---|
53 | png_structp png_ptr = nullptr;
|
---|
54 | png_infop end_info_ptr = nullptr;
|
---|
55 | png_voidp row_ptr = nullptr;
|
---|
56 | BufState* buf_state = nullptr;
|
---|
57 |
|
---|
58 | ~PngObjectHandler() {
|
---|
59 | if (row_ptr)
|
---|
60 | png_free(png_ptr, row_ptr);
|
---|
61 | if (end_info_ptr)
|
---|
62 | png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
|
---|
63 | else if (info_ptr)
|
---|
64 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
---|
65 | else
|
---|
66 | png_destroy_read_struct(&png_ptr, nullptr, nullptr);
|
---|
67 | delete buf_state;
|
---|
68 | }
|
---|
69 | };
|
---|
70 |
|
---|
71 | void user_read_data(png_structp png_ptr, png_bytep data, size_t length) {
|
---|
72 | BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr));
|
---|
73 | if (length > buf_state->bytes_left) {
|
---|
74 | png_error(png_ptr, "read error");
|
---|
75 | }
|
---|
76 | memcpy(data, buf_state->data, length);
|
---|
77 | buf_state->bytes_left -= length;
|
---|
78 | buf_state->data += length;
|
---|
79 | }
|
---|
80 |
|
---|
81 | static const int kPngHeaderSize = 8;
|
---|
82 |
|
---|
83 | // Entry point for LibFuzzer.
|
---|
84 | // Roughly follows the libpng book example:
|
---|
85 | // http://www.libpng.org/pub/png/book/chapter13.html
|
---|
86 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
---|
87 | if (size < kPngHeaderSize) {
|
---|
88 | return 0;
|
---|
89 | }
|
---|
90 |
|
---|
91 | std::vector<unsigned char> v(data, data + size);
|
---|
92 | if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) {
|
---|
93 | // not a PNG.
|
---|
94 | return 0;
|
---|
95 | }
|
---|
96 |
|
---|
97 | PngObjectHandler png_handler;
|
---|
98 | png_handler.png_ptr = nullptr;
|
---|
99 | png_handler.row_ptr = nullptr;
|
---|
100 | png_handler.info_ptr = nullptr;
|
---|
101 | png_handler.end_info_ptr = nullptr;
|
---|
102 |
|
---|
103 | png_handler.png_ptr = png_create_read_struct
|
---|
104 | (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
---|
105 | if (!png_handler.png_ptr) {
|
---|
106 | return 0;
|
---|
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 | png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
|
---|
122 | #ifdef PNG_IGNORE_ADLER32
|
---|
123 | png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
|
---|
124 | #endif
|
---|
125 |
|
---|
126 | // Setting up reading from buffer.
|
---|
127 | png_handler.buf_state = new BufState();
|
---|
128 | png_handler.buf_state->data = data + kPngHeaderSize;
|
---|
129 | png_handler.buf_state->bytes_left = size - kPngHeaderSize;
|
---|
130 | png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);
|
---|
131 | png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);
|
---|
132 |
|
---|
133 | if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
|
---|
134 | PNG_CLEANUP
|
---|
135 | return 0;
|
---|
136 | }
|
---|
137 |
|
---|
138 | // Reading.
|
---|
139 | png_read_info(png_handler.png_ptr, png_handler.info_ptr);
|
---|
140 |
|
---|
141 | // reset error handler to put png_deleter into scope.
|
---|
142 | if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
|
---|
143 | PNG_CLEANUP
|
---|
144 | return 0;
|
---|
145 | }
|
---|
146 |
|
---|
147 | png_uint_32 width, height;
|
---|
148 | int bit_depth, color_type, interlace_type, compression_type;
|
---|
149 | int filter_type;
|
---|
150 |
|
---|
151 | if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,
|
---|
152 | &height, &bit_depth, &color_type, &interlace_type,
|
---|
153 | &compression_type, &filter_type)) {
|
---|
154 | PNG_CLEANUP
|
---|
155 | return 0;
|
---|
156 | }
|
---|
157 |
|
---|
158 | // This is going to be too slow.
|
---|
159 | if (width && height > 100000000 / width) {
|
---|
160 | PNG_CLEANUP
|
---|
161 | return 0;
|
---|
162 | }
|
---|
163 |
|
---|
164 | // Set several transforms that browsers typically use:
|
---|
165 | png_set_gray_to_rgb(png_handler.png_ptr);
|
---|
166 | png_set_expand(png_handler.png_ptr);
|
---|
167 | png_set_packing(png_handler.png_ptr);
|
---|
168 | png_set_scale_16(png_handler.png_ptr);
|
---|
169 | png_set_tRNS_to_alpha(png_handler.png_ptr);
|
---|
170 |
|
---|
171 | int passes = png_set_interlace_handling(png_handler.png_ptr);
|
---|
172 |
|
---|
173 | png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);
|
---|
174 |
|
---|
175 | png_handler.row_ptr = png_malloc(
|
---|
176 | png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,
|
---|
177 | png_handler.info_ptr));
|
---|
178 |
|
---|
179 | for (int pass = 0; pass < passes; ++pass) {
|
---|
180 | for (png_uint_32 y = 0; y < height; ++y) {
|
---|
181 | png_read_row(png_handler.png_ptr,
|
---|
182 | static_cast<png_bytep>(png_handler.row_ptr), nullptr);
|
---|
183 | }
|
---|
184 | }
|
---|
185 |
|
---|
186 | png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
|
---|
187 |
|
---|
188 | PNG_CLEANUP
|
---|
189 | return 0;
|
---|
190 | }
|
---|