Coverage Report

Created: 2022-11-20 06:11

/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
}
LLVMFuzzerTestOneInput
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
}
FuzzPNG
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
}