/src/libpng/contrib/oss-fuzz/libpng_read_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
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 | 26.3k | if(png_handler.png_ptr) \ |
29 | 26.3k | { \ |
30 | 26.3k | if (png_handler.row_ptr) \ |
31 | 26.3k | png_free(png_handler.png_ptr, png_handler.row_ptr); \ |
32 | 26.3k | if (png_handler.end_info_ptr) \ |
33 | 26.3k | png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ |
34 | 26.3k | &png_handler.end_info_ptr); \ |
35 | 26.3k | else if (png_handler.info_ptr) \ |
36 | 0 | png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ |
37 | 0 | nullptr); \ |
38 | 0 | else \ |
39 | 0 | png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \ |
40 | 26.3k | png_handler.png_ptr = nullptr; \ |
41 | 26.3k | png_handler.row_ptr = nullptr; \ |
42 | 26.3k | png_handler.info_ptr = nullptr; \ |
43 | 26.3k | png_handler.end_info_ptr = nullptr; \ |
44 | 26.3k | } |
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 | 26.3k | ~PngObjectHandler() { |
59 | 26.3k | if (row_ptr) |
60 | 0 | png_free(png_ptr, row_ptr); |
61 | 26.3k | if (end_info_ptr) |
62 | 0 | png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); |
63 | 26.3k | else if (info_ptr) |
64 | 0 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
65 | 26.3k | else |
66 | 26.3k | png_destroy_read_struct(&png_ptr, nullptr, nullptr); |
67 | 26.3k | delete buf_state; |
68 | 26.3k | } |
69 | | }; |
70 | | |
71 | 3.53M | void user_read_data(png_structp png_ptr, png_bytep data, size_t length) { |
72 | 3.53M | BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr)); |
73 | 3.53M | if (length > buf_state->bytes_left) { |
74 | 5.87k | png_error(png_ptr, "read error"); |
75 | 5.87k | } |
76 | 3.52M | memcpy(data, buf_state->data, length); |
77 | 3.52M | buf_state->bytes_left -= length; |
78 | 3.52M | buf_state->data += length; |
79 | 3.52M | } |
80 | | |
81 | 150k | void* limited_malloc(png_structp, png_alloc_size_t size) { |
82 | | // libpng may allocate large amounts of memory that the fuzzer reports as |
83 | | // an error. In order to silence these errors, make libpng fail when trying |
84 | | // to allocate a large amount. This allocator used to be in the Chromium |
85 | | // version of this fuzzer. |
86 | | // This number is chosen to match the default png_user_chunk_malloc_max. |
87 | 150k | if (size > 8000000) |
88 | 2.08k | return nullptr; |
89 | | |
90 | 148k | return malloc(size); |
91 | 150k | } |
92 | | |
93 | 227k | void default_free(png_structp, png_voidp ptr) { |
94 | 227k | return free(ptr); |
95 | 227k | } |
96 | | |
97 | | static const int kPngHeaderSize = 8; |
98 | | |
99 | | // Entry point for LibFuzzer. |
100 | | // Roughly follows the libpng book example: |
101 | | // http://www.libpng.org/pub/png/book/chapter13.html |
102 | 26.3k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
103 | 26.3k | if (size < kPngHeaderSize) { |
104 | 4 | return 0; |
105 | 4 | } |
106 | | |
107 | 26.3k | std::vector<unsigned char> v(data, data + size); |
108 | 26.3k | if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { |
109 | | // not a PNG. |
110 | 77 | return 0; |
111 | 77 | } |
112 | | |
113 | 26.3k | PngObjectHandler png_handler; |
114 | 26.3k | png_handler.png_ptr = nullptr; |
115 | 26.3k | png_handler.row_ptr = nullptr; |
116 | 26.3k | png_handler.info_ptr = nullptr; |
117 | 26.3k | png_handler.end_info_ptr = nullptr; |
118 | | |
119 | 26.3k | png_handler.png_ptr = png_create_read_struct |
120 | 26.3k | (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
121 | 26.3k | if (!png_handler.png_ptr) { |
122 | 0 | return 0; |
123 | 0 | } |
124 | | |
125 | 26.3k | png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); |
126 | 26.3k | if (!png_handler.info_ptr) { |
127 | 0 | PNG_CLEANUP |
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | 26.3k | png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); |
132 | 26.3k | if (!png_handler.end_info_ptr) { |
133 | 0 | PNG_CLEANUP |
134 | 0 | return 0; |
135 | 0 | } |
136 | | |
137 | | // Use a custom allocator that fails for large allocations to avoid OOM. |
138 | 26.3k | png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free); |
139 | | |
140 | 26.3k | png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); |
141 | 26.3k | #ifdef PNG_IGNORE_ADLER32 |
142 | 26.3k | png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); |
143 | 26.3k | #endif |
144 | | |
145 | | // Setting up reading from buffer. |
146 | 26.3k | png_handler.buf_state = new BufState(); |
147 | 26.3k | png_handler.buf_state->data = data + kPngHeaderSize; |
148 | 26.3k | png_handler.buf_state->bytes_left = size - kPngHeaderSize; |
149 | 26.3k | png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); |
150 | 26.3k | png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); |
151 | | |
152 | 26.3k | if (setjmp(png_jmpbuf(png_handler.png_ptr))) { |
153 | 20.2k | PNG_CLEANUP |
154 | 20.2k | return 0; |
155 | 20.2k | } |
156 | | |
157 | | // Reading. |
158 | 6.02k | png_read_info(png_handler.png_ptr, png_handler.info_ptr); |
159 | | |
160 | | // reset error handler to put png_deleter into scope. |
161 | 6.02k | if (setjmp(png_jmpbuf(png_handler.png_ptr))) { |
162 | 4.49k | PNG_CLEANUP |
163 | 4.49k | return 0; |
164 | 4.49k | } |
165 | | |
166 | 1.52k | png_uint_32 width, height; |
167 | 1.52k | int bit_depth, color_type, interlace_type, compression_type; |
168 | 1.52k | int filter_type; |
169 | | |
170 | 1.52k | if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, |
171 | 1.52k | &height, &bit_depth, &color_type, &interlace_type, |
172 | 1.52k | &compression_type, &filter_type)) { |
173 | 0 | PNG_CLEANUP |
174 | 0 | return 0; |
175 | 0 | } |
176 | | |
177 | | // This is going to be too slow. |
178 | 6.02k | if (width && height > 100000000 / width) { |
179 | 69 | PNG_CLEANUP |
180 | 69 | return 0; |
181 | 69 | } |
182 | | |
183 | | // Set several transforms that browsers typically use: |
184 | 1.45k | png_set_gray_to_rgb(png_handler.png_ptr); |
185 | 1.45k | png_set_expand(png_handler.png_ptr); |
186 | 1.45k | png_set_packing(png_handler.png_ptr); |
187 | 1.45k | png_set_scale_16(png_handler.png_ptr); |
188 | 1.45k | png_set_tRNS_to_alpha(png_handler.png_ptr); |
189 | | |
190 | 1.45k | int passes = png_set_interlace_handling(png_handler.png_ptr); |
191 | | |
192 | 1.45k | png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); |
193 | | |
194 | 1.45k | png_handler.row_ptr = png_malloc( |
195 | 1.45k | png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, |
196 | 1.45k | png_handler.info_ptr)); |
197 | | |
198 | 16.6k | for (int pass = 0; pass < passes; ++pass) { |
199 | 410k | for (png_uint_32 y = 0; y < height; ++y) { |
200 | 395k | png_read_row(png_handler.png_ptr, |
201 | 395k | static_cast<png_bytep>(png_handler.row_ptr), nullptr); |
202 | 395k | } |
203 | 15.1k | } |
204 | | |
205 | 1.45k | png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); |
206 | | |
207 | 1.45k | PNG_CLEANUP |
208 | 1.45k | return 0; |
209 | 1.52k | } Line | Count | Source | 102 | 7.93k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 103 | 7.93k | if (size < kPngHeaderSize) { | 104 | 4 | return 0; | 105 | 4 | } | 106 | | | 107 | 7.92k | std::vector<unsigned char> v(data, data + size); | 108 | 7.92k | if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { | 109 | | // not a PNG. | 110 | 77 | return 0; | 111 | 77 | } | 112 | | | 113 | 7.84k | PngObjectHandler png_handler; | 114 | 7.84k | png_handler.png_ptr = nullptr; | 115 | 7.84k | png_handler.row_ptr = nullptr; | 116 | 7.84k | png_handler.info_ptr = nullptr; | 117 | 7.84k | png_handler.end_info_ptr = nullptr; | 118 | | | 119 | 7.84k | png_handler.png_ptr = png_create_read_struct | 120 | 7.84k | (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); | 121 | 7.84k | if (!png_handler.png_ptr) { | 122 | 0 | return 0; | 123 | 0 | } | 124 | | | 125 | 7.84k | png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); | 126 | 7.84k | if (!png_handler.info_ptr) { | 127 | 0 | PNG_CLEANUP | 128 | 0 | return 0; | 129 | 0 | } | 130 | | | 131 | 7.84k | png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); | 132 | 7.84k | if (!png_handler.end_info_ptr) { | 133 | 0 | PNG_CLEANUP | 134 | 0 | return 0; | 135 | 0 | } | 136 | | | 137 | | // Use a custom allocator that fails for large allocations to avoid OOM. | 138 | 7.84k | png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free); | 139 | | | 140 | 7.84k | png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); | 141 | 7.84k | #ifdef PNG_IGNORE_ADLER32 | 142 | 7.84k | png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); | 143 | 7.84k | #endif | 144 | | | 145 | | // Setting up reading from buffer. | 146 | 7.84k | png_handler.buf_state = new BufState(); | 147 | 7.84k | png_handler.buf_state->data = data + kPngHeaderSize; | 148 | 7.84k | png_handler.buf_state->bytes_left = size - kPngHeaderSize; | 149 | 7.84k | png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); | 150 | 7.84k | png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); | 151 | | | 152 | 7.84k | if (setjmp(png_jmpbuf(png_handler.png_ptr))) { | 153 | 6.16k | PNG_CLEANUP | 154 | 6.16k | return 0; | 155 | 6.16k | } | 156 | | | 157 | | // Reading. | 158 | 1.68k | png_read_info(png_handler.png_ptr, png_handler.info_ptr); | 159 | | | 160 | | // reset error handler to put png_deleter into scope. | 161 | 1.68k | if (setjmp(png_jmpbuf(png_handler.png_ptr))) { | 162 | 1.55k | PNG_CLEANUP | 163 | 1.55k | return 0; | 164 | 1.55k | } | 165 | | | 166 | 130 | png_uint_32 width, height; | 167 | 130 | int bit_depth, color_type, interlace_type, compression_type; | 168 | 130 | int filter_type; | 169 | | | 170 | 130 | if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, | 171 | 130 | &height, &bit_depth, &color_type, &interlace_type, | 172 | 130 | &compression_type, &filter_type)) { | 173 | 0 | PNG_CLEANUP | 174 | 0 | return 0; | 175 | 0 | } | 176 | | | 177 | | // This is going to be too slow. | 178 | 1.68k | if (width && height > 100000000 / width) { | 179 | 69 | PNG_CLEANUP | 180 | 69 | return 0; | 181 | 69 | } | 182 | | | 183 | | // Set several transforms that browsers typically use: | 184 | 61 | png_set_gray_to_rgb(png_handler.png_ptr); | 185 | 61 | png_set_expand(png_handler.png_ptr); | 186 | 61 | png_set_packing(png_handler.png_ptr); | 187 | 61 | png_set_scale_16(png_handler.png_ptr); | 188 | 61 | png_set_tRNS_to_alpha(png_handler.png_ptr); | 189 | | | 190 | 61 | int passes = png_set_interlace_handling(png_handler.png_ptr); | 191 | | | 192 | 61 | png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); | 193 | | | 194 | 61 | png_handler.row_ptr = png_malloc( | 195 | 61 | png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, | 196 | 61 | png_handler.info_ptr)); | 197 | | | 198 | 3.66k | for (int pass = 0; pass < passes; ++pass) { | 199 | 248k | for (png_uint_32 y = 0; y < height; ++y) { | 200 | 245k | png_read_row(png_handler.png_ptr, | 201 | 245k | static_cast<png_bytep>(png_handler.row_ptr), nullptr); | 202 | 245k | } | 203 | 3.60k | } | 204 | | | 205 | 61 | png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); | 206 | | | 207 | 61 | PNG_CLEANUP | 208 | 61 | return 0; | 209 | 130 | } |
Line | Count | Source | 102 | 18.4k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 103 | 18.4k | if (size < kPngHeaderSize) { | 104 | 0 | return 0; | 105 | 0 | } | 106 | | | 107 | 18.4k | std::vector<unsigned char> v(data, data + size); | 108 | 18.4k | if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { | 109 | | // not a PNG. | 110 | 0 | return 0; | 111 | 0 | } | 112 | | | 113 | 18.4k | PngObjectHandler png_handler; | 114 | 18.4k | png_handler.png_ptr = nullptr; | 115 | 18.4k | png_handler.row_ptr = nullptr; | 116 | 18.4k | png_handler.info_ptr = nullptr; | 117 | 18.4k | png_handler.end_info_ptr = nullptr; | 118 | | | 119 | 18.4k | png_handler.png_ptr = png_create_read_struct | 120 | 18.4k | (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); | 121 | 18.4k | if (!png_handler.png_ptr) { | 122 | 0 | return 0; | 123 | 0 | } | 124 | | | 125 | 18.4k | png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); | 126 | 18.4k | if (!png_handler.info_ptr) { | 127 | 0 | PNG_CLEANUP | 128 | 0 | return 0; | 129 | 0 | } | 130 | | | 131 | 18.4k | png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); | 132 | 18.4k | if (!png_handler.end_info_ptr) { | 133 | 0 | PNG_CLEANUP | 134 | 0 | return 0; | 135 | 0 | } | 136 | | | 137 | | // Use a custom allocator that fails for large allocations to avoid OOM. | 138 | 18.4k | png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free); | 139 | | | 140 | 18.4k | png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); | 141 | 18.4k | #ifdef PNG_IGNORE_ADLER32 | 142 | 18.4k | png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); | 143 | 18.4k | #endif | 144 | | | 145 | | // Setting up reading from buffer. | 146 | 18.4k | png_handler.buf_state = new BufState(); | 147 | 18.4k | png_handler.buf_state->data = data + kPngHeaderSize; | 148 | 18.4k | png_handler.buf_state->bytes_left = size - kPngHeaderSize; | 149 | 18.4k | png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); | 150 | 18.4k | png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); | 151 | | | 152 | 18.4k | if (setjmp(png_jmpbuf(png_handler.png_ptr))) { | 153 | 14.1k | PNG_CLEANUP | 154 | 14.1k | return 0; | 155 | 14.1k | } | 156 | | | 157 | | // Reading. | 158 | 4.33k | png_read_info(png_handler.png_ptr, png_handler.info_ptr); | 159 | | | 160 | | // reset error handler to put png_deleter into scope. | 161 | 4.33k | if (setjmp(png_jmpbuf(png_handler.png_ptr))) { | 162 | 2.94k | PNG_CLEANUP | 163 | 2.94k | return 0; | 164 | 2.94k | } | 165 | | | 166 | 1.39k | png_uint_32 width, height; | 167 | 1.39k | int bit_depth, color_type, interlace_type, compression_type; | 168 | 1.39k | int filter_type; | 169 | | | 170 | 1.39k | if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, | 171 | 1.39k | &height, &bit_depth, &color_type, &interlace_type, | 172 | 1.39k | &compression_type, &filter_type)) { | 173 | 0 | PNG_CLEANUP | 174 | 0 | return 0; | 175 | 0 | } | 176 | | | 177 | | // This is going to be too slow. | 178 | 4.33k | if (width && height > 100000000 / width) { | 179 | 0 | PNG_CLEANUP | 180 | 0 | return 0; | 181 | 0 | } | 182 | | | 183 | | // Set several transforms that browsers typically use: | 184 | 1.39k | png_set_gray_to_rgb(png_handler.png_ptr); | 185 | 1.39k | png_set_expand(png_handler.png_ptr); | 186 | 1.39k | png_set_packing(png_handler.png_ptr); | 187 | 1.39k | png_set_scale_16(png_handler.png_ptr); | 188 | 1.39k | png_set_tRNS_to_alpha(png_handler.png_ptr); | 189 | | | 190 | 1.39k | int passes = png_set_interlace_handling(png_handler.png_ptr); | 191 | | | 192 | 1.39k | png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); | 193 | | | 194 | 1.39k | png_handler.row_ptr = png_malloc( | 195 | 1.39k | png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, | 196 | 1.39k | png_handler.info_ptr)); | 197 | | | 198 | 12.9k | for (int pass = 0; pass < passes; ++pass) { | 199 | 161k | for (png_uint_32 y = 0; y < height; ++y) { | 200 | 149k | png_read_row(png_handler.png_ptr, | 201 | 149k | static_cast<png_bytep>(png_handler.row_ptr), nullptr); | 202 | 149k | } | 203 | 11.5k | } | 204 | | | 205 | 1.39k | png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); | 206 | | | 207 | 1.39k | PNG_CLEANUP | 208 | 1.39k | return 0; | 209 | 1.39k | } |
|