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