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
Get(const uint64_t id)34 template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) {
35 (void)id;
36 switch ( Get<uint8_t>() ) {
37 case 0:
38 return FLAC__METADATA_TYPE_STREAMINFO;
39 case 1:
40 return FLAC__METADATA_TYPE_PADDING;
41 case 2:
42 return FLAC__METADATA_TYPE_APPLICATION;
43 case 3:
44 return FLAC__METADATA_TYPE_SEEKTABLE;
45 case 4:
46 return FLAC__METADATA_TYPE_VORBIS_COMMENT;
47 case 5:
48 return FLAC__METADATA_TYPE_CUESHEET;
49 case 6:
50 return FLAC__METADATA_TYPE_PICTURE;
51 case 7:
52 return FLAC__METADATA_TYPE_UNDEFINED;
53 case 8:
54 return FLAC__MAX_METADATA_TYPE;
55 default:
56 return FLAC__METADATA_TYPE_STREAMINFO;
57 }
58 }
59
60 namespace FLAC {
61 namespace Decoder {
62 class FuzzerStream : public Stream {
63 private:
64 fuzzing::datasource::Datasource& ds;
65 public:
FuzzerStream(fuzzing::datasource::Datasource & dsrc)66 FuzzerStream(fuzzing::datasource::Datasource& dsrc) :
67 Stream(), ds(dsrc) { }
68
read_callback(FLAC__byte buffer[],size_t * bytes)69 ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override {
70 try {
71 const size_t maxCopySize = *bytes;
72
73 if ( maxCopySize > 0 ) {
74 /* memset just to test if this overwrites anything, and triggers ASAN */
75 memset(buffer, 0, maxCopySize);
76 }
77
78 const auto data = ds.GetData(0);
79 const auto dataSize = data.size();
80 const auto copySize = std::min(maxCopySize, dataSize);
81
82 if ( copySize > 0 ) {
83 memcpy(buffer, data.data(), copySize);
84 }
85
86 *bytes = copySize;
87
88 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
89 } catch ( ... ) {
90 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
91 }
92 }
93
write_callback(const::FLAC__Frame * frame,const FLAC__int32 * const buffer[])94 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override {
95 {
96 fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header));
97 fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer));
98 }
99
100 {
101 const auto numChannels = get_channels();
102 const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32);
103 for (size_t i = 0; i < numChannels; i++) {
104 fuzzing::memory::memory_test(buffer[i], bytesPerChannel);
105 }
106 }
107
108 try {
109 if ( ds.Get<bool>() == true ) {
110 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
111 }
112 } catch ( ... ) { }
113 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
114 }
115
error_callback(::FLAC__StreamDecoderErrorStatus status)116 void error_callback(::FLAC__StreamDecoderErrorStatus status) override {
117 fuzzing::memory::memory_test(status);
118 }
119
metadata_callback(const::FLAC__StreamMetadata * metadata)120 void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
121 Metadata::Prototype * cloned_object = nullptr;
122 fuzzing::memory::memory_test(metadata->type);
123 fuzzing::memory::memory_test(metadata->is_last);
124 fuzzing::memory::memory_test(metadata->length);
125 fuzzing::memory::memory_test(metadata->data);
126 if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
127 cloned_object = new Metadata::StreamInfo(metadata);
128 else if (metadata->type == FLAC__METADATA_TYPE_PADDING)
129 cloned_object = new Metadata::Padding(metadata);
130 else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION)
131 cloned_object = new Metadata::Application(metadata);
132 else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE)
133 cloned_object = new Metadata::SeekTable(metadata);
134 else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
135 cloned_object = new Metadata::VorbisComment(metadata);
136 else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET)
137 cloned_object = new Metadata::CueSheet(metadata);
138 else if (metadata->type == FLAC__METADATA_TYPE_PICTURE)
139 cloned_object = new Metadata::Picture(metadata);
140 else
141 return;
142 if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) {
143 if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE)
144 dynamic_cast<Metadata::SeekTable *>(cloned_object)->is_legal();
145 if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE)
146 dynamic_cast<Metadata::Picture *>(cloned_object)->is_legal(NULL);
147 if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET)
148 dynamic_cast<Metadata::CueSheet *>(cloned_object)->is_legal(true,NULL);
149 }
150 delete cloned_object;
151 }
152
seek_callback(FLAC__uint64 absolute_byte_offset)153 ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override {
154 fuzzing::memory::memory_test(absolute_byte_offset);
155
156 try {
157 if ( ds.Get<bool>() == true ) {
158 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
159 } else {
160 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
161 }
162 } catch ( ... ) {
163 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
164 }
165 }
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
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)199 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
200 fuzzing::datasource::Datasource ds(data, size);
201 FLAC::Decoder::FuzzerStream decoder(ds);
202 bool use_ogg = true;
203
204 try {
205 if ( ds.Get<bool>() ) {
206 use_ogg = false;
207 }
208 if ( ds.Get<bool>() ) {
209 #ifdef FUZZER_DEBUG
210 printf("set_ogg_serial_number\n");
211 #endif
212 decoder.set_ogg_serial_number(ds.Get<long>());
213 }
214 if ( ds.Get<bool>() ) {
215 #ifdef FUZZER_DEBUG
216 printf("set_md5_checking\n");
217 #endif
218 decoder.set_md5_checking(ds.Get<bool>());
219 }
220 if ( ds.Get<bool>() ) {
221 #ifdef FUZZER_DEBUG
222 printf("set_metadata_respond\n");
223 #endif
224 decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>());
225 }
226 if ( ds.Get<bool>() ) {
227 const auto idVector = ds.GetData(0);
228 unsigned char id[4];
229 if ( idVector.size() >= sizeof(id) ) {
230 memcpy(id, idVector.data(), sizeof(id));
231 #ifdef FUZZER_DEBUG
232 printf("set_metadata_respond_application\n");
233 #endif
234 decoder.set_metadata_respond_application(id);
235 }
236 }
237 if ( ds.Get<bool>() ) {
238 #ifdef FUZZER_DEBUG
239 printf("set_metadata_respond_all\n");
240 #endif
241 decoder.set_metadata_respond_all();
242 }
243 if ( ds.Get<bool>() ) {
244 #ifdef FUZZER_DEBUG
245 printf("set_metadata_ignore\n");
246 #endif
247 decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>());
248 }
249 if ( ds.Get<bool>() ) {
250 const auto idVector = ds.GetData(0);
251 unsigned char id[4];
252 if ( idVector.size() >= sizeof(id) ) {
253 memcpy(id, idVector.data(), sizeof(id));
254 #ifdef FUZZER_DEBUG
255 printf("set_metadata_ignore_application\n");
256 #endif
257 decoder.set_metadata_ignore_application(id);
258 }
259 }
260 if ( ds.Get<bool>() ) {
261 #ifdef FUZZER_DEBUG
262 printf("set_metadata_ignore_all\n");
263 #endif
264 decoder.set_metadata_ignore_all();
265 }
266 {
267 ::FLAC__StreamDecoderInitStatus ret;
268 if ( !use_ogg ) {
269 ret = decoder.init();
270 } else {
271 ret = decoder.init_ogg();
272 }
273
274 if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
275 goto end;
276 }
277 }
278
279 while ( ds.Get<bool>() ) {
280 switch ( ds.Get<uint8_t>() ) {
281 case 0:
282 {
283 #ifdef FUZZER_DEBUG
284 printf("flush\n");
285 #endif
286 const bool res = decoder.flush();
287 fuzzing::memory::memory_test(res);
288 }
289 break;
290 case 1:
291 {
292 #ifdef FUZZER_DEBUG
293 printf("reset\n");
294 #endif
295 const bool res = decoder.reset();
296 fuzzing::memory::memory_test(res);
297 }
298 break;
299 case 2:
300 {
301 #ifdef FUZZER_DEBUG
302 printf("process_single\n");
303 #endif
304 const bool res = decoder.process_single();
305 fuzzing::memory::memory_test(res);
306 }
307 break;
308 case 3:
309 {
310 #ifdef FUZZER_DEBUG
311 printf("process_until_end_of_metadata\n");
312 #endif
313 const bool res = decoder.process_until_end_of_metadata();
314 fuzzing::memory::memory_test(res);
315 }
316 break;
317 case 4:
318 {
319 #ifdef FUZZER_DEBUG
320 printf("process_until_end_of_stream\n");
321 #endif
322 const bool res = decoder.process_until_end_of_stream();
323 fuzzing::memory::memory_test(res);
324 }
325 break;
326 case 5:
327 {
328 #ifdef FUZZER_DEBUG
329 printf("skip_single_frame\n");
330 #endif
331 const bool res = decoder.skip_single_frame();
332 fuzzing::memory::memory_test(res);
333 }
334 break;
335 case 6:
336 {
337 #ifdef FUZZER_DEBUG
338 printf("seek_absolute\n");
339 #endif
340 const bool res = decoder.seek_absolute(ds.Get<uint64_t>());
341 fuzzing::memory::memory_test(res);
342 }
343 break;
344 case 7:
345 {
346 #ifdef FUZZER_DEBUG
347 printf("get_md5_checking\n");
348 #endif
349 const bool res = decoder.get_md5_checking();
350 fuzzing::memory::memory_test(res);
351 }
352 break;
353 case 8:
354 {
355 #ifdef FUZZER_DEBUG
356 printf("get_total_samples\n");
357 #endif
358 const bool res = decoder.get_total_samples();
359 fuzzing::memory::memory_test(res);
360 }
361 break;
362 case 9:
363 {
364 #ifdef FUZZER_DEBUG
365 printf("get_channels\n");
366 #endif
367 const bool res = decoder.get_channels();
368 fuzzing::memory::memory_test(res);
369 }
370 break;
371 case 10:
372 {
373 #ifdef FUZZER_DEBUG
374 printf("get_bits_per_sample\n");
375 #endif
376 const bool res = decoder.get_bits_per_sample();
377 fuzzing::memory::memory_test(res);
378 }
379 break;
380 case 11:
381 {
382 #ifdef FUZZER_DEBUG
383 printf("get_sample_rate\n");
384 #endif
385 const bool res = decoder.get_sample_rate();
386 fuzzing::memory::memory_test(res);
387 }
388 break;
389 case 12:
390 {
391 #ifdef FUZZER_DEBUG
392 printf("get_blocksize\n");
393 #endif
394 const bool res = decoder.get_blocksize();
395 fuzzing::memory::memory_test(res);
396 }
397 break;
398 }
399 }
400 } catch ( ... ) { }
401
402 end:
403 {
404 const bool res = decoder.finish();
405 fuzzing::memory::memory_test(res);
406 }
407 return 0;
408 }
409