/src/flac/oss-fuzz/decoder.cc
Line | Count | Source |
1 | | /* Copyright 2019 Guido Vranken |
2 | | * |
3 | | * Permission is hereby granted, free of charge, to any person obtaining |
4 | | * a copy of this software and associated documentation files (the |
5 | | * "Software"), to deal in the Software without restriction, including |
6 | | * without limitation the rights to use, copy, modify, merge, publish, |
7 | | * distribute, sublicense, and/or sell copies of the Software, and to |
8 | | * permit persons to whom the Software is furnished to do so, subject |
9 | | * to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be |
12 | | * included in all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
15 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
16 | | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
17 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
18 | | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
19 | | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
20 | | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | | * SOFTWARE. |
22 | | */ |
23 | | |
24 | | #include <cstddef> |
25 | | #include <cstdint> |
26 | | |
27 | | #include <fuzzing/datasource/datasource.hpp> |
28 | | #include <fuzzing/memory.hpp> |
29 | | |
30 | | #include "FLAC++/decoder.h" |
31 | | #include "FLAC++/metadata.h" |
32 | | #include "common.h" |
33 | | |
34 | 137 | template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) { |
35 | 137 | (void)id; |
36 | 137 | switch ( Get<uint8_t>() ) { |
37 | 20 | case 0: |
38 | 20 | return FLAC__METADATA_TYPE_STREAMINFO; |
39 | 11 | case 1: |
40 | 11 | return FLAC__METADATA_TYPE_PADDING; |
41 | 5 | case 2: |
42 | 5 | return FLAC__METADATA_TYPE_APPLICATION; |
43 | 5 | case 3: |
44 | 5 | return FLAC__METADATA_TYPE_SEEKTABLE; |
45 | 1 | case 4: |
46 | 1 | return FLAC__METADATA_TYPE_VORBIS_COMMENT; |
47 | 4 | case 5: |
48 | 4 | return FLAC__METADATA_TYPE_CUESHEET; |
49 | 0 | case 6: |
50 | 0 | return FLAC__METADATA_TYPE_PICTURE; |
51 | 4 | case 7: |
52 | 4 | return FLAC__METADATA_TYPE_UNDEFINED; |
53 | 4 | case 8: |
54 | 4 | return FLAC__MAX_METADATA_TYPE; |
55 | 81 | default: |
56 | 81 | return FLAC__METADATA_TYPE_STREAMINFO; |
57 | 137 | } |
58 | 137 | } |
59 | | |
60 | | namespace FLAC { |
61 | | namespace Decoder { |
62 | | class FuzzerStream : public Stream { |
63 | | private: |
64 | | fuzzing::datasource::Datasource& ds; |
65 | | public: |
66 | | FuzzerStream(fuzzing::datasource::Datasource& dsrc) : |
67 | 8.95k | Stream(), ds(dsrc) { } |
68 | | |
69 | 157k | ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override { |
70 | 157k | try { |
71 | 157k | const size_t maxCopySize = *bytes; |
72 | | |
73 | 157k | if ( maxCopySize > 0 ) { |
74 | | /* memset just to test if this overwrites anything, and triggers ASAN */ |
75 | 157k | memset(buffer, 0, maxCopySize); |
76 | 157k | } |
77 | | |
78 | 157k | const auto data = ds.GetData(0); |
79 | 157k | const auto dataSize = data.size(); |
80 | 157k | const auto copySize = std::min(maxCopySize, dataSize); |
81 | | |
82 | 157k | if ( copySize > 0 ) { |
83 | 82.3k | memcpy(buffer, data.data(), copySize); |
84 | 82.3k | } |
85 | | |
86 | 157k | *bytes = copySize; |
87 | | |
88 | 157k | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
89 | 157k | } catch ( ... ) { |
90 | 61.1k | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
91 | 61.1k | } |
92 | 157k | } |
93 | | |
94 | 74.6k | ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override { |
95 | 74.6k | { |
96 | 74.6k | fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header)); |
97 | 74.6k | fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer)); |
98 | 74.6k | } |
99 | | |
100 | 74.6k | { |
101 | 74.6k | const auto numChannels = get_channels(); |
102 | 74.6k | const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32); |
103 | 220k | for (size_t i = 0; i < numChannels; i++) { |
104 | 145k | fuzzing::memory::memory_test(buffer[i], bytesPerChannel); |
105 | 145k | } |
106 | 74.6k | } |
107 | | |
108 | 74.6k | try { |
109 | 74.6k | if ( ds.Get<bool>() == true ) { |
110 | 879 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
111 | 879 | } |
112 | 74.6k | } catch ( ... ) { } |
113 | 73.7k | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
114 | 74.6k | } |
115 | | |
116 | 259k | void error_callback(::FLAC__StreamDecoderErrorStatus status) override { |
117 | 259k | fuzzing::memory::memory_test(status); |
118 | 259k | } |
119 | | |
120 | 26.3k | void metadata_callback(const ::FLAC__StreamMetadata *metadata) override { |
121 | 26.3k | Metadata::Prototype * cloned_object = nullptr; |
122 | 26.3k | fuzzing::memory::memory_test(metadata->type); |
123 | 26.3k | fuzzing::memory::memory_test(metadata->is_last); |
124 | 26.3k | fuzzing::memory::memory_test(metadata->length); |
125 | 26.3k | fuzzing::memory::memory_test(metadata->data); |
126 | 26.3k | if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) |
127 | 1.86k | cloned_object = new Metadata::StreamInfo(metadata); |
128 | 24.4k | else if (metadata->type == FLAC__METADATA_TYPE_PADDING) |
129 | 922 | cloned_object = new Metadata::Padding(metadata); |
130 | 23.5k | else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) |
131 | 3.31k | cloned_object = new Metadata::Application(metadata); |
132 | 20.2k | else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) |
133 | 1.71k | cloned_object = new Metadata::SeekTable(metadata); |
134 | 18.5k | else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) |
135 | 1.67k | cloned_object = new Metadata::VorbisComment(metadata); |
136 | 16.8k | else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET) |
137 | 4.53k | cloned_object = new Metadata::CueSheet(metadata); |
138 | 12.2k | else if (metadata->type == FLAC__METADATA_TYPE_PICTURE) |
139 | 8.35k | cloned_object = new Metadata::Picture(metadata); |
140 | 3.93k | else |
141 | 3.93k | return; |
142 | 22.3k | if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) { |
143 | 22.3k | if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE) |
144 | 1.71k | dynamic_cast<Metadata::SeekTable *>(cloned_object)->is_legal(); |
145 | 22.3k | if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE) |
146 | 8.28k | dynamic_cast<Metadata::Picture *>(cloned_object)->is_legal(NULL); |
147 | 22.3k | if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET) |
148 | 4.53k | dynamic_cast<Metadata::CueSheet *>(cloned_object)->is_legal(true,NULL); |
149 | 22.3k | } |
150 | 22.3k | delete cloned_object; |
151 | 22.3k | } |
152 | | |
153 | 84.8k | ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override { |
154 | 84.8k | fuzzing::memory::memory_test(absolute_byte_offset); |
155 | | |
156 | 84.8k | try { |
157 | 84.8k | if ( ds.Get<bool>() == true ) { |
158 | 80.5k | return FLAC__STREAM_DECODER_SEEK_STATUS_OK; |
159 | 80.5k | } else { |
160 | 4.31k | return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; |
161 | 4.31k | } |
162 | 84.8k | } catch ( ... ) { |
163 | 34 | return FLAC__STREAM_DECODER_SEEK_STATUS_OK; |
164 | 34 | } |
165 | 84.8k | } |
166 | | #if 0 |
167 | | ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override { |
168 | | fuzzing::memory::memory_test(*absolute_byte_offset); |
169 | | |
170 | | try { |
171 | | if ( ds.Get<bool>() == true ) { |
172 | | return FLAC__STREAM_DECODER_TELL_STATUS_OK; |
173 | | } else { |
174 | | return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; |
175 | | } |
176 | | } catch ( ... ) { |
177 | | return FLAC__STREAM_DECODER_TELL_STATUS_OK; |
178 | | } |
179 | | } |
180 | | |
181 | | ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override { |
182 | | fuzzing::memory::memory_test(*stream_length); |
183 | | |
184 | | try { |
185 | | if ( ds.Get<bool>() == true ) { |
186 | | return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; |
187 | | } else { |
188 | | return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; |
189 | | } |
190 | | } catch ( ... ) { |
191 | | return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; |
192 | | } |
193 | | } |
194 | | #endif |
195 | | }; |
196 | | } |
197 | | } |
198 | | |
199 | 8.95k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
200 | 8.95k | fuzzing::datasource::Datasource ds(data, size); |
201 | 8.95k | FLAC::Decoder::FuzzerStream decoder(ds); |
202 | 8.95k | bool use_ogg = true; |
203 | | |
204 | 8.95k | try { |
205 | 8.95k | if ( ds.Get<bool>() ) { |
206 | 7.76k | use_ogg = false; |
207 | 7.76k | } |
208 | | |
209 | 8.95k | decoder.set_decode_chained_stream(true); |
210 | | |
211 | 8.95k | if ( ds.Get<bool>() ) { |
212 | | #ifdef FUZZER_DEBUG |
213 | | printf("set_ogg_serial_number\n"); |
214 | | #endif |
215 | 36 | decoder.set_ogg_serial_number(ds.Get<long>()); |
216 | 36 | } |
217 | 8.95k | if ( ds.Get<bool>() ) { |
218 | | #ifdef FUZZER_DEBUG |
219 | | printf("set_md5_checking\n"); |
220 | | #endif |
221 | 1.34k | decoder.set_md5_checking(ds.Get<bool>()); |
222 | 1.34k | } |
223 | 8.95k | if ( ds.Get<bool>() ) { |
224 | | #ifdef FUZZER_DEBUG |
225 | | printf("set_metadata_respond\n"); |
226 | | #endif |
227 | 59 | decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>()); |
228 | 59 | } |
229 | 8.95k | if ( ds.Get<bool>() ) { |
230 | 60 | const auto idVector = ds.GetData(0); |
231 | 60 | unsigned char id[4]; |
232 | 60 | if ( idVector.size() >= sizeof(id) ) { |
233 | 18 | memcpy(id, idVector.data(), sizeof(id)); |
234 | | #ifdef FUZZER_DEBUG |
235 | | printf("set_metadata_respond_application\n"); |
236 | | #endif |
237 | 18 | decoder.set_metadata_respond_application(id); |
238 | 18 | } |
239 | 60 | } |
240 | 8.95k | if ( ds.Get<bool>() ) { |
241 | | #ifdef FUZZER_DEBUG |
242 | | printf("set_metadata_respond_all\n"); |
243 | | #endif |
244 | 4.82k | decoder.set_metadata_respond_all(); |
245 | 4.82k | } |
246 | 8.95k | if ( ds.Get<bool>() ) { |
247 | | #ifdef FUZZER_DEBUG |
248 | | printf("set_metadata_ignore\n"); |
249 | | #endif |
250 | 78 | decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>()); |
251 | 78 | } |
252 | 8.95k | if ( ds.Get<bool>() ) { |
253 | 71 | const auto idVector = ds.GetData(0); |
254 | 71 | unsigned char id[4]; |
255 | 71 | if ( idVector.size() >= sizeof(id) ) { |
256 | 63 | memcpy(id, idVector.data(), sizeof(id)); |
257 | | #ifdef FUZZER_DEBUG |
258 | | printf("set_metadata_ignore_application\n"); |
259 | | #endif |
260 | 63 | decoder.set_metadata_ignore_application(id); |
261 | 63 | } |
262 | 71 | } |
263 | 8.95k | if ( ds.Get<bool>() ) { |
264 | | #ifdef FUZZER_DEBUG |
265 | | printf("set_metadata_ignore_all\n"); |
266 | | #endif |
267 | 3.06k | decoder.set_metadata_ignore_all(); |
268 | 3.06k | } |
269 | 8.95k | { |
270 | 8.95k | ::FLAC__StreamDecoderInitStatus ret; |
271 | 8.95k | if ( !use_ogg ) { |
272 | 7.68k | ret = decoder.init(); |
273 | 7.68k | } else { |
274 | 1.26k | ret = decoder.init_ogg(); |
275 | 1.26k | } |
276 | | |
277 | 8.95k | if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) { |
278 | 0 | goto end; |
279 | 0 | } |
280 | 8.95k | } |
281 | | |
282 | 295k | while ( ds.Get<bool>() ) { |
283 | 286k | switch ( ds.Get<uint8_t>() ) { |
284 | 12.7k | case 0: |
285 | 12.7k | { |
286 | | #ifdef FUZZER_DEBUG |
287 | | printf("flush\n"); |
288 | | #endif |
289 | 12.7k | const bool res = decoder.flush(); |
290 | 12.7k | fuzzing::memory::memory_test(res); |
291 | 12.7k | } |
292 | 12.7k | break; |
293 | 85.1k | case 1: |
294 | 85.1k | { |
295 | | #ifdef FUZZER_DEBUG |
296 | | printf("reset\n"); |
297 | | #endif |
298 | 85.1k | const bool res = decoder.reset(); |
299 | 85.1k | fuzzing::memory::memory_test(res); |
300 | 85.1k | } |
301 | 85.1k | break; |
302 | 16.4k | case 2: |
303 | 16.4k | { |
304 | | #ifdef FUZZER_DEBUG |
305 | | printf("process_single\n"); |
306 | | #endif |
307 | 16.4k | const bool res = decoder.process_single(); |
308 | 16.4k | fuzzing::memory::memory_test(res); |
309 | 16.4k | } |
310 | 16.4k | break; |
311 | 84.0k | case 3: |
312 | 84.0k | { |
313 | | #ifdef FUZZER_DEBUG |
314 | | printf("process_until_end_of_metadata\n"); |
315 | | #endif |
316 | 84.0k | const bool res = decoder.process_until_end_of_metadata(); |
317 | 84.0k | fuzzing::memory::memory_test(res); |
318 | 84.0k | } |
319 | 84.0k | break; |
320 | 27.8k | case 4: |
321 | 27.8k | { |
322 | | #ifdef FUZZER_DEBUG |
323 | | printf("process_until_end_of_stream\n"); |
324 | | #endif |
325 | 27.8k | const bool res = decoder.process_until_end_of_stream(); |
326 | 27.8k | fuzzing::memory::memory_test(res); |
327 | 27.8k | } |
328 | 27.8k | break; |
329 | 1.77k | case 5: |
330 | 1.77k | { |
331 | | #ifdef FUZZER_DEBUG |
332 | | printf("skip_single_frame\n"); |
333 | | #endif |
334 | 1.77k | const bool res = decoder.skip_single_frame(); |
335 | 1.77k | fuzzing::memory::memory_test(res); |
336 | 1.77k | } |
337 | 1.77k | break; |
338 | 1.09k | case 6: |
339 | 1.09k | { |
340 | | #ifdef FUZZER_DEBUG |
341 | | printf("seek_absolute\n"); |
342 | | #endif |
343 | 1.09k | const bool res = decoder.seek_absolute(ds.Get<uint64_t>()); |
344 | 1.09k | fuzzing::memory::memory_test(res); |
345 | 1.09k | } |
346 | 1.09k | break; |
347 | 268 | case 7: |
348 | 268 | { |
349 | | #ifdef FUZZER_DEBUG |
350 | | printf("get_md5_checking\n"); |
351 | | #endif |
352 | 268 | const bool res = decoder.get_md5_checking(); |
353 | 268 | fuzzing::memory::memory_test(res); |
354 | 268 | } |
355 | 268 | break; |
356 | 807 | case 8: |
357 | 807 | { |
358 | | #ifdef FUZZER_DEBUG |
359 | | printf("get_total_samples\n"); |
360 | | #endif |
361 | 807 | const bool res = decoder.get_total_samples(); |
362 | 807 | fuzzing::memory::memory_test(res); |
363 | 807 | } |
364 | 807 | break; |
365 | 477 | case 9: |
366 | 477 | { |
367 | | #ifdef FUZZER_DEBUG |
368 | | printf("get_channels\n"); |
369 | | #endif |
370 | 477 | const bool res = decoder.get_channels(); |
371 | 477 | fuzzing::memory::memory_test(res); |
372 | 477 | } |
373 | 477 | break; |
374 | 1.57k | case 10: |
375 | 1.57k | { |
376 | | #ifdef FUZZER_DEBUG |
377 | | printf("get_bits_per_sample\n"); |
378 | | #endif |
379 | 1.57k | const bool res = decoder.get_bits_per_sample(); |
380 | 1.57k | fuzzing::memory::memory_test(res); |
381 | 1.57k | } |
382 | 1.57k | break; |
383 | 627 | case 11: |
384 | 627 | { |
385 | | #ifdef FUZZER_DEBUG |
386 | | printf("get_sample_rate\n"); |
387 | | #endif |
388 | 627 | const bool res = decoder.get_sample_rate(); |
389 | 627 | fuzzing::memory::memory_test(res); |
390 | 627 | } |
391 | 627 | break; |
392 | 298 | case 12: |
393 | 298 | { |
394 | | #ifdef FUZZER_DEBUG |
395 | | printf("get_blocksize\n"); |
396 | | #endif |
397 | 298 | const bool res = decoder.get_blocksize(); |
398 | 298 | fuzzing::memory::memory_test(res); |
399 | 298 | } |
400 | 298 | break; |
401 | 286k | } |
402 | 286k | } |
403 | 8.95k | } catch ( ... ) { } |
404 | | |
405 | 8.95k | end: |
406 | 8.95k | { |
407 | 8.95k | const bool res = decoder.finish(); |
408 | 8.95k | fuzzing::memory::memory_test(res); |
409 | 8.95k | } |
410 | 8.95k | return 0; |
411 | 8.95k | } |