1*a67afe4dSAndroid Build Coastguard Worker
2*a67afe4dSAndroid Build Coastguard Worker // libpng_read_fuzzer.cc
3*a67afe4dSAndroid Build Coastguard Worker // Copyright 2017-2018 Glenn Randers-Pehrson
4*a67afe4dSAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors. All rights reserved.
5*a67afe4dSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that may
6*a67afe4dSAndroid Build Coastguard Worker // be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE
7*a67afe4dSAndroid Build Coastguard Worker
8*a67afe4dSAndroid Build Coastguard Worker // The modifications in 2017 by Glenn Randers-Pehrson include
9*a67afe4dSAndroid Build Coastguard Worker // 1. addition of a PNG_CLEANUP macro,
10*a67afe4dSAndroid Build Coastguard Worker // 2. setting the option to ignore ADLER32 checksums,
11*a67afe4dSAndroid Build Coastguard Worker // 3. adding "#include <string.h>" which is needed on some platforms
12*a67afe4dSAndroid Build Coastguard Worker // to provide memcpy().
13*a67afe4dSAndroid Build Coastguard Worker // 4. adding read_end_info() and creating an end_info structure.
14*a67afe4dSAndroid Build Coastguard Worker // 5. adding calls to png_set_*() transforms commonly used by browsers.
15*a67afe4dSAndroid Build Coastguard Worker
16*a67afe4dSAndroid Build Coastguard Worker #include <stddef.h>
17*a67afe4dSAndroid Build Coastguard Worker #include <stdint.h>
18*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
19*a67afe4dSAndroid Build Coastguard Worker #include <string.h>
20*a67afe4dSAndroid Build Coastguard Worker
21*a67afe4dSAndroid Build Coastguard Worker #include <vector>
22*a67afe4dSAndroid Build Coastguard Worker
23*a67afe4dSAndroid Build Coastguard Worker #define PNG_INTERNAL
24*a67afe4dSAndroid Build Coastguard Worker #include "png.h"
25*a67afe4dSAndroid Build Coastguard Worker
26*a67afe4dSAndroid Build Coastguard Worker #define PNG_CLEANUP \
27*a67afe4dSAndroid Build Coastguard Worker if(png_handler.png_ptr) \
28*a67afe4dSAndroid Build Coastguard Worker { \
29*a67afe4dSAndroid Build Coastguard Worker if (png_handler.row_ptr) \
30*a67afe4dSAndroid Build Coastguard Worker png_free(png_handler.png_ptr, png_handler.row_ptr); \
31*a67afe4dSAndroid Build Coastguard Worker if (png_handler.end_info_ptr) \
32*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
33*a67afe4dSAndroid Build Coastguard Worker &png_handler.end_info_ptr); \
34*a67afe4dSAndroid Build Coastguard Worker else if (png_handler.info_ptr) \
35*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
36*a67afe4dSAndroid Build Coastguard Worker nullptr); \
37*a67afe4dSAndroid Build Coastguard Worker else \
38*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \
39*a67afe4dSAndroid Build Coastguard Worker png_handler.png_ptr = nullptr; \
40*a67afe4dSAndroid Build Coastguard Worker png_handler.row_ptr = nullptr; \
41*a67afe4dSAndroid Build Coastguard Worker png_handler.info_ptr = nullptr; \
42*a67afe4dSAndroid Build Coastguard Worker png_handler.end_info_ptr = nullptr; \
43*a67afe4dSAndroid Build Coastguard Worker }
44*a67afe4dSAndroid Build Coastguard Worker
45*a67afe4dSAndroid Build Coastguard Worker struct BufState {
46*a67afe4dSAndroid Build Coastguard Worker const uint8_t* data;
47*a67afe4dSAndroid Build Coastguard Worker size_t bytes_left;
48*a67afe4dSAndroid Build Coastguard Worker };
49*a67afe4dSAndroid Build Coastguard Worker
50*a67afe4dSAndroid Build Coastguard Worker struct PngObjectHandler {
51*a67afe4dSAndroid Build Coastguard Worker png_infop info_ptr = nullptr;
52*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr = nullptr;
53*a67afe4dSAndroid Build Coastguard Worker png_infop end_info_ptr = nullptr;
54*a67afe4dSAndroid Build Coastguard Worker png_voidp row_ptr = nullptr;
55*a67afe4dSAndroid Build Coastguard Worker BufState* buf_state = nullptr;
56*a67afe4dSAndroid Build Coastguard Worker
~PngObjectHandlerPngObjectHandler57*a67afe4dSAndroid Build Coastguard Worker ~PngObjectHandler() {
58*a67afe4dSAndroid Build Coastguard Worker if (row_ptr)
59*a67afe4dSAndroid Build Coastguard Worker png_free(png_ptr, row_ptr);
60*a67afe4dSAndroid Build Coastguard Worker if (end_info_ptr)
61*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
62*a67afe4dSAndroid Build Coastguard Worker else if (info_ptr)
63*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
64*a67afe4dSAndroid Build Coastguard Worker else
65*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, nullptr, nullptr);
66*a67afe4dSAndroid Build Coastguard Worker delete buf_state;
67*a67afe4dSAndroid Build Coastguard Worker }
68*a67afe4dSAndroid Build Coastguard Worker };
69*a67afe4dSAndroid Build Coastguard Worker
user_read_data(png_structp png_ptr,png_bytep data,size_t length)70*a67afe4dSAndroid Build Coastguard Worker void user_read_data(png_structp png_ptr, png_bytep data, size_t length) {
71*a67afe4dSAndroid Build Coastguard Worker BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr));
72*a67afe4dSAndroid Build Coastguard Worker if (length > buf_state->bytes_left) {
73*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "read error");
74*a67afe4dSAndroid Build Coastguard Worker }
75*a67afe4dSAndroid Build Coastguard Worker memcpy(data, buf_state->data, length);
76*a67afe4dSAndroid Build Coastguard Worker buf_state->bytes_left -= length;
77*a67afe4dSAndroid Build Coastguard Worker buf_state->data += length;
78*a67afe4dSAndroid Build Coastguard Worker }
79*a67afe4dSAndroid Build Coastguard Worker
limited_malloc(png_structp,png_alloc_size_t size)80*a67afe4dSAndroid Build Coastguard Worker void* limited_malloc(png_structp, png_alloc_size_t size) {
81*a67afe4dSAndroid Build Coastguard Worker // libpng may allocate large amounts of memory that the fuzzer reports as
82*a67afe4dSAndroid Build Coastguard Worker // an error. In order to silence these errors, make libpng fail when trying
83*a67afe4dSAndroid Build Coastguard Worker // to allocate a large amount. This allocator used to be in the Chromium
84*a67afe4dSAndroid Build Coastguard Worker // version of this fuzzer.
85*a67afe4dSAndroid Build Coastguard Worker // This number is chosen to match the default png_user_chunk_malloc_max.
86*a67afe4dSAndroid Build Coastguard Worker if (size > 8000000)
87*a67afe4dSAndroid Build Coastguard Worker return nullptr;
88*a67afe4dSAndroid Build Coastguard Worker
89*a67afe4dSAndroid Build Coastguard Worker return malloc(size);
90*a67afe4dSAndroid Build Coastguard Worker }
91*a67afe4dSAndroid Build Coastguard Worker
default_free(png_structp,png_voidp ptr)92*a67afe4dSAndroid Build Coastguard Worker void default_free(png_structp, png_voidp ptr) {
93*a67afe4dSAndroid Build Coastguard Worker return free(ptr);
94*a67afe4dSAndroid Build Coastguard Worker }
95*a67afe4dSAndroid Build Coastguard Worker
96*a67afe4dSAndroid Build Coastguard Worker static const int kPngHeaderSize = 8;
97*a67afe4dSAndroid Build Coastguard Worker
98*a67afe4dSAndroid Build Coastguard Worker // Entry point for LibFuzzer.
99*a67afe4dSAndroid Build Coastguard Worker // Roughly follows the libpng book example:
100*a67afe4dSAndroid Build Coastguard Worker // http://www.libpng.org/pub/png/book/chapter13.html
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)101*a67afe4dSAndroid Build Coastguard Worker extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
102*a67afe4dSAndroid Build Coastguard Worker if (size < kPngHeaderSize) {
103*a67afe4dSAndroid Build Coastguard Worker return 0;
104*a67afe4dSAndroid Build Coastguard Worker }
105*a67afe4dSAndroid Build Coastguard Worker
106*a67afe4dSAndroid Build Coastguard Worker std::vector<unsigned char> v(data, data + size);
107*a67afe4dSAndroid Build Coastguard Worker if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) {
108*a67afe4dSAndroid Build Coastguard Worker // not a PNG.
109*a67afe4dSAndroid Build Coastguard Worker return 0;
110*a67afe4dSAndroid Build Coastguard Worker }
111*a67afe4dSAndroid Build Coastguard Worker
112*a67afe4dSAndroid Build Coastguard Worker PngObjectHandler png_handler;
113*a67afe4dSAndroid Build Coastguard Worker png_handler.png_ptr = nullptr;
114*a67afe4dSAndroid Build Coastguard Worker png_handler.row_ptr = nullptr;
115*a67afe4dSAndroid Build Coastguard Worker png_handler.info_ptr = nullptr;
116*a67afe4dSAndroid Build Coastguard Worker png_handler.end_info_ptr = nullptr;
117*a67afe4dSAndroid Build Coastguard Worker
118*a67afe4dSAndroid Build Coastguard Worker png_handler.png_ptr = png_create_read_struct
119*a67afe4dSAndroid Build Coastguard Worker (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
120*a67afe4dSAndroid Build Coastguard Worker if (!png_handler.png_ptr) {
121*a67afe4dSAndroid Build Coastguard Worker return 0;
122*a67afe4dSAndroid Build Coastguard Worker }
123*a67afe4dSAndroid Build Coastguard Worker
124*a67afe4dSAndroid Build Coastguard Worker png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);
125*a67afe4dSAndroid Build Coastguard Worker if (!png_handler.info_ptr) {
126*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
127*a67afe4dSAndroid Build Coastguard Worker return 0;
128*a67afe4dSAndroid Build Coastguard Worker }
129*a67afe4dSAndroid Build Coastguard Worker
130*a67afe4dSAndroid Build Coastguard Worker png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);
131*a67afe4dSAndroid Build Coastguard Worker if (!png_handler.end_info_ptr) {
132*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
133*a67afe4dSAndroid Build Coastguard Worker return 0;
134*a67afe4dSAndroid Build Coastguard Worker }
135*a67afe4dSAndroid Build Coastguard Worker
136*a67afe4dSAndroid Build Coastguard Worker // Use a custom allocator that fails for large allocations to avoid OOM.
137*a67afe4dSAndroid Build Coastguard Worker png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free);
138*a67afe4dSAndroid Build Coastguard Worker
139*a67afe4dSAndroid Build Coastguard Worker png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
140*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_IGNORE_ADLER32
141*a67afe4dSAndroid Build Coastguard Worker png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
142*a67afe4dSAndroid Build Coastguard Worker #endif
143*a67afe4dSAndroid Build Coastguard Worker
144*a67afe4dSAndroid Build Coastguard Worker // Setting up reading from buffer.
145*a67afe4dSAndroid Build Coastguard Worker png_handler.buf_state = new BufState();
146*a67afe4dSAndroid Build Coastguard Worker png_handler.buf_state->data = data + kPngHeaderSize;
147*a67afe4dSAndroid Build Coastguard Worker png_handler.buf_state->bytes_left = size - kPngHeaderSize;
148*a67afe4dSAndroid Build Coastguard Worker png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);
149*a67afe4dSAndroid Build Coastguard Worker png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);
150*a67afe4dSAndroid Build Coastguard Worker
151*a67afe4dSAndroid Build Coastguard Worker if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
152*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
153*a67afe4dSAndroid Build Coastguard Worker return 0;
154*a67afe4dSAndroid Build Coastguard Worker }
155*a67afe4dSAndroid Build Coastguard Worker
156*a67afe4dSAndroid Build Coastguard Worker // Reading.
157*a67afe4dSAndroid Build Coastguard Worker png_read_info(png_handler.png_ptr, png_handler.info_ptr);
158*a67afe4dSAndroid Build Coastguard Worker
159*a67afe4dSAndroid Build Coastguard Worker // reset error handler to put png_deleter into scope.
160*a67afe4dSAndroid Build Coastguard Worker if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
161*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
162*a67afe4dSAndroid Build Coastguard Worker return 0;
163*a67afe4dSAndroid Build Coastguard Worker }
164*a67afe4dSAndroid Build Coastguard Worker
165*a67afe4dSAndroid Build Coastguard Worker png_uint_32 width, height;
166*a67afe4dSAndroid Build Coastguard Worker int bit_depth, color_type, interlace_type, compression_type;
167*a67afe4dSAndroid Build Coastguard Worker int filter_type;
168*a67afe4dSAndroid Build Coastguard Worker
169*a67afe4dSAndroid Build Coastguard Worker if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,
170*a67afe4dSAndroid Build Coastguard Worker &height, &bit_depth, &color_type, &interlace_type,
171*a67afe4dSAndroid Build Coastguard Worker &compression_type, &filter_type)) {
172*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
173*a67afe4dSAndroid Build Coastguard Worker return 0;
174*a67afe4dSAndroid Build Coastguard Worker }
175*a67afe4dSAndroid Build Coastguard Worker
176*a67afe4dSAndroid Build Coastguard Worker // This is going to be too slow.
177*a67afe4dSAndroid Build Coastguard Worker if (width && height > 100000000 / width) {
178*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
179*a67afe4dSAndroid Build Coastguard Worker return 0;
180*a67afe4dSAndroid Build Coastguard Worker }
181*a67afe4dSAndroid Build Coastguard Worker
182*a67afe4dSAndroid Build Coastguard Worker // Set several transforms that browsers typically use:
183*a67afe4dSAndroid Build Coastguard Worker png_set_gray_to_rgb(png_handler.png_ptr);
184*a67afe4dSAndroid Build Coastguard Worker png_set_expand(png_handler.png_ptr);
185*a67afe4dSAndroid Build Coastguard Worker png_set_packing(png_handler.png_ptr);
186*a67afe4dSAndroid Build Coastguard Worker png_set_scale_16(png_handler.png_ptr);
187*a67afe4dSAndroid Build Coastguard Worker png_set_tRNS_to_alpha(png_handler.png_ptr);
188*a67afe4dSAndroid Build Coastguard Worker
189*a67afe4dSAndroid Build Coastguard Worker int passes = png_set_interlace_handling(png_handler.png_ptr);
190*a67afe4dSAndroid Build Coastguard Worker
191*a67afe4dSAndroid Build Coastguard Worker png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);
192*a67afe4dSAndroid Build Coastguard Worker
193*a67afe4dSAndroid Build Coastguard Worker png_handler.row_ptr = png_malloc(
194*a67afe4dSAndroid Build Coastguard Worker png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,
195*a67afe4dSAndroid Build Coastguard Worker png_handler.info_ptr));
196*a67afe4dSAndroid Build Coastguard Worker
197*a67afe4dSAndroid Build Coastguard Worker for (int pass = 0; pass < passes; ++pass) {
198*a67afe4dSAndroid Build Coastguard Worker for (png_uint_32 y = 0; y < height; ++y) {
199*a67afe4dSAndroid Build Coastguard Worker png_read_row(png_handler.png_ptr,
200*a67afe4dSAndroid Build Coastguard Worker static_cast<png_bytep>(png_handler.row_ptr), nullptr);
201*a67afe4dSAndroid Build Coastguard Worker }
202*a67afe4dSAndroid Build Coastguard Worker }
203*a67afe4dSAndroid Build Coastguard Worker
204*a67afe4dSAndroid Build Coastguard Worker png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
205*a67afe4dSAndroid Build Coastguard Worker
206*a67afe4dSAndroid Build Coastguard Worker PNG_CLEANUP
207*a67afe4dSAndroid Build Coastguard Worker
208*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SIMPLIFIED_READ_SUPPORTED
209*a67afe4dSAndroid Build Coastguard Worker // Simplified READ API
210*a67afe4dSAndroid Build Coastguard Worker png_image image;
211*a67afe4dSAndroid Build Coastguard Worker memset(&image, 0, (sizeof image));
212*a67afe4dSAndroid Build Coastguard Worker image.version = PNG_IMAGE_VERSION;
213*a67afe4dSAndroid Build Coastguard Worker
214*a67afe4dSAndroid Build Coastguard Worker if (!png_image_begin_read_from_memory(&image, data, size)) {
215*a67afe4dSAndroid Build Coastguard Worker return 0;
216*a67afe4dSAndroid Build Coastguard Worker }
217*a67afe4dSAndroid Build Coastguard Worker
218*a67afe4dSAndroid Build Coastguard Worker image.format = PNG_FORMAT_RGBA;
219*a67afe4dSAndroid Build Coastguard Worker std::vector<png_byte> buffer(PNG_IMAGE_SIZE(image));
220*a67afe4dSAndroid Build Coastguard Worker png_image_finish_read(&image, NULL, buffer.data(), 0, NULL);
221*a67afe4dSAndroid Build Coastguard Worker #endif
222*a67afe4dSAndroid Build Coastguard Worker
223*a67afe4dSAndroid Build Coastguard Worker return 0;
224*a67afe4dSAndroid Build Coastguard Worker }
225