You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
12 KiB
356 lines
12 KiB
#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;
|
|
}
|