xref: /aosp_15_r20/external/flac/oss-fuzz/decoder.cc (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
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