| #include <cstddef> |
| #include <cstdint> |
| |
| #include <fuzzing/datasource/datasource.hpp> |
| #include <fuzzing/memory.hpp> |
| |
| #include "FLAC++/decoder.h" |
| |
| template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) { |
| (void)id; |
| switch ( Get<uint8_t>() ) { |
| case 0: |
| return FLAC__METADATA_TYPE_STREAMINFO; |
| case 1: |
| return FLAC__METADATA_TYPE_PADDING; |
| case 2: |
| return FLAC__METADATA_TYPE_APPLICATION; |
| case 3: |
| return FLAC__METADATA_TYPE_SEEKTABLE; |
| case 4: |
| return FLAC__METADATA_TYPE_VORBIS_COMMENT; |
| case 5: |
| return FLAC__METADATA_TYPE_CUESHEET; |
| case 6: |
| return FLAC__METADATA_TYPE_PICTURE; |
| case 7: |
| return FLAC__METADATA_TYPE_UNDEFINED; |
| case 8: |
| return FLAC__MAX_METADATA_TYPE; |
| default: |
| return FLAC__METADATA_TYPE_STREAMINFO; |
| } |
| } |
| |
| namespace FLAC { |
| namespace Decoder { |
| class FuzzerStream : public Stream { |
| private: |
| fuzzing::datasource::Datasource& ds; |
| public: |
| FuzzerStream(fuzzing::datasource::Datasource& dsrc) : |
| Stream(), ds(dsrc) { } |
| |
| ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override { |
| try { |
| const size_t maxCopySize = *bytes; |
| |
| if ( maxCopySize > 0 ) { |
| /* memset just to test if this overwrites anything, and triggers ASAN */ |
| memset(buffer, 0, maxCopySize); |
| } |
| |
| const auto data = ds.GetData(0); |
| const auto dataSize = data.size(); |
| const auto copySize = std::min(maxCopySize, dataSize); |
| |
| if ( copySize > 0 ) { |
| memcpy(buffer, data.data(), copySize); |
| } |
| |
| *bytes = copySize; |
| |
| return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
| } catch ( ... ) { |
| return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
| } |
| } |
| |
| ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override { |
| { |
| fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header)); |
| fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer)); |
| } |
| |
| { |
| const auto numChannels = get_channels(); |
| const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32); |
| for (size_t i = 0; i < numChannels; i++) { |
| fuzzing::memory::memory_test(buffer[i], bytesPerChannel); |
| } |
| } |
| |
| try { |
| if ( ds.Get<bool>() == true ) { |
| return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
| } |
| } catch ( ... ) { } |
| return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
| } |
| |
| void error_callback(::FLAC__StreamDecoderErrorStatus status) override { |
| fuzzing::memory::memory_test(status); |
| } |
| |
| void metadata_callback(const ::FLAC__StreamMetadata *metadata) override { |
| fuzzing::memory::memory_test(metadata->type); |
| fuzzing::memory::memory_test(metadata->is_last); |
| fuzzing::memory::memory_test(metadata->length); |
| fuzzing::memory::memory_test(metadata->data); |
| } |
| |
| ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override { |
| fuzzing::memory::memory_test(absolute_byte_offset); |
| |
| try { |
| if ( ds.Get<bool>() == true ) { |
| return FLAC__STREAM_DECODER_SEEK_STATUS_OK; |
| } else { |
| return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; |
| } |
| } catch ( ... ) { |
| return FLAC__STREAM_DECODER_SEEK_STATUS_OK; |
| } |
| } |
| #if 0 |
| ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override { |
| fuzzing::memory::memory_test(*absolute_byte_offset); |
| |
| try { |
| if ( ds.Get<bool>() == true ) { |
| return FLAC__STREAM_DECODER_TELL_STATUS_OK; |
| } else { |
| return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; |
| } |
| } catch ( ... ) { |
| return FLAC__STREAM_DECODER_TELL_STATUS_OK; |
| } |
| } |
| |
| ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override { |
| fuzzing::memory::memory_test(*stream_length); |
| |
| try { |
| if ( ds.Get<bool>() == true ) { |
| return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; |
| } else { |
| return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; |
| } |
| } catch ( ... ) { |
| return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; |
| } |
| } |
| #endif |
| }; |
| } |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
| fuzzing::datasource::Datasource ds(data, size); |
| FLAC::Decoder::FuzzerStream decoder(ds); |
| |
| try { |
| { |
| ::FLAC__StreamDecoderInitStatus ret; |
| |
| if ( ds.Get<bool>() ) { |
| ret = decoder.init(); |
| } else { |
| ret = decoder.init_ogg(); |
| } |
| |
| if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) { |
| goto end; |
| } |
| } |
| |
| if ( ds.Get<bool>() ) { |
| #ifdef FUZZER_DEBUG |
| printf("set_ogg_serial_number\n"); |
| #endif |
| decoder.set_ogg_serial_number(ds.Get<long>()); |
| } |
| if ( ds.Get<bool>() ) { |
| #ifdef FUZZER_DEBUG |
| printf("set_md5_checking\n"); |
| #endif |
| decoder.set_md5_checking(ds.Get<bool>()); |
| } |
| if ( ds.Get<bool>() ) { |
| #ifdef FUZZER_DEBUG |
| printf("set_metadata_respond\n"); |
| #endif |
| decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>()); |
| } |
| if ( ds.Get<bool>() ) { |
| const auto idVector = ds.GetData(0); |
| unsigned char id[4]; |
| if ( idVector.size() >= sizeof(id) ) { |
| memcpy(id, idVector.data(), sizeof(id)); |
| #ifdef FUZZER_DEBUG |
| printf("set_metadata_respond_application\n"); |
| #endif |
| decoder.set_metadata_respond_application(id); |
| } |
| } |
| if ( ds.Get<bool>() ) { |
| #ifdef FUZZER_DEBUG |
| printf("set_metadata_respond_all\n"); |
| #endif |
| decoder.set_metadata_respond_all(); |
| } |
| if ( ds.Get<bool>() ) { |
| #ifdef FUZZER_DEBUG |
| printf("set_metadata_ignore\n"); |
| #endif |
| decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>()); |
| } |
| if ( ds.Get<bool>() ) { |
| const auto idVector = ds.GetData(0); |
| unsigned char id[4]; |
| if ( idVector.size() >= sizeof(id) ) { |
| memcpy(id, idVector.data(), sizeof(id)); |
| #ifdef FUZZER_DEBUG |
| printf("set_metadata_ignore_application\n"); |
| #endif |
| decoder.set_metadata_ignore_application(id); |
| } |
| } |
| if ( ds.Get<bool>() ) { |
| #ifdef FUZZER_DEBUG |
| printf("set_metadata_ignore_all\n"); |
| #endif |
| decoder.set_metadata_ignore_all(); |
| } |
| |
| while ( ds.Get<bool>() ) { |
| switch ( ds.Get<uint8_t>() ) { |
| case 0: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("flush\n"); |
| #endif |
| const bool res = decoder.flush(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 1: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("reset\n"); |
| #endif |
| const bool res = decoder.reset(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 2: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("process_single\n"); |
| #endif |
| const bool res = decoder.process_single(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 3: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("process_until_end_of_metadata\n"); |
| #endif |
| const bool res = decoder.process_until_end_of_metadata(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 4: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("process_until_end_of_stream\n"); |
| #endif |
| const bool res = decoder.process_until_end_of_stream(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 5: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("skip_single_frame\n"); |
| #endif |
| const bool res = decoder.skip_single_frame(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 6: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("seek_absolute\n"); |
| #endif |
| const bool res = decoder.seek_absolute(ds.Get<uint64_t>()); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 7: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("get_md5_checking\n"); |
| #endif |
| const bool res = decoder.get_md5_checking(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 8: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("get_total_samples\n"); |
| #endif |
| const bool res = decoder.get_total_samples(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 9: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("get_channels\n"); |
| #endif |
| const bool res = decoder.get_channels(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 10: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("get_bits_per_sample\n"); |
| #endif |
| const bool res = decoder.get_bits_per_sample(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 11: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("get_sample_rate\n"); |
| #endif |
| const bool res = decoder.get_sample_rate(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| case 12: |
| { |
| #ifdef FUZZER_DEBUG |
| printf("get_blocksize\n"); |
| #endif |
| const bool res = decoder.get_blocksize(); |
| fuzzing::memory::memory_test(res); |
| } |
| break; |
| } |
| } |
| } catch ( ... ) { } |
| |
| end: |
| { |
| const bool res = decoder.finish(); |
| fuzzing::memory::memory_test(res); |
| } |
| return 0; |
| } |