初始化内容

This commit is contained in:
2026-09-16 14:07:40 +08:00
parent 6934b390bf
commit 4f643c1e7c
18350 changed files with 6088489 additions and 305 deletions
+104
View File
@@ -0,0 +1,104 @@
# FLAC - Free Lossless Audio Codec
# Copyright (C) 2019-2023 Xiph.Org Foundation
#
# This file is part the FLAC project. FLAC is comprised of several
# components distributed under different licenses. The codec libraries
# are distributed under Xiph.Org's BSD-like license (see the file
# COPYING.Xiph in this distribution). All other programs, libraries, and
# plugins are distributed under the GPL (see COPYING.GPL). The documentation
# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
# FLAC distribution contains at the top the terms under which it may be
# distributed.
#
# Since this particular file is relevant to all components of FLAC,
# it may be distributed under the Xiph.Org license, which is the least
# restrictive of those mentioned above. See the file COPYING.Xiph in this
# distribution.
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/oss-fuzz
AM_CFLAGS = ${LIB_FUZZING_ENGINE}
AM_CXXFLAGS = -std=c++11 $(LIB_FUZZING_ENGINE)
LDADD = $(flac_libs)
EXTRA_DIST = \
fuzzer_encoder.dict \
common.h \
Readme.md \
fuzzing/datasource/datasource.hpp \
fuzzing/datasource/id.hpp \
fuzzing/exception.hpp \
fuzzing/memory.hpp \
fuzzing/types.hpp
noinst_PROGRAMS =
if USE_OSSFUZZERS
noinst_PROGRAMS += fuzzer_encoder fuzzer_encoder_v2 fuzzer_decoder fuzzer_seek fuzzer_metadata fuzzer_reencoder fuzzer_tool_flac fuzzer_tool_metaflac
endif
fuzzer_encoder_SOURCES = encoder.cc
fuzzer_encoder_v2_SOURCES = encoder_v2.cc
fuzzer_decoder_SOURCES = decoder.cc
fuzzer_seek_SOURCES = seek.cc
fuzzer_metadata_SOURCES = metadata.cc
fuzzer_reencoder_SOURCES = reencoder.cc
fuzzer_tool_flac_SOURCES = ${flac_SOURCES} empty.cc tool_flac.c # empty.cc is to force use of C++ linker, which is mandated by oss-fuzz
fuzzer_tool_flac_LDADD = \
$(top_builddir)/src/share/utf8/libutf8.la \
$(top_builddir)/src/share/grabbag/libgrabbag.la \
$(top_builddir)/src/share/getopt/libgetopt.la \
$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
$(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
$(top_builddir)/src/libFLAC/libFLAC.la \
@LTLIBICONV@ \
-lm
fuzzer_tool_metaflac_SOURCES = ${metaflac_SOURCES} empty.cc tool_metaflac.c # empty.cc is to force use of C++ linker, which is mandated by oss-fuzz
fuzzer_tool_metaflac_LDADD = \
$(top_builddir)/src/share/utf8/libutf8.la \
$(top_builddir)/src/share/grabbag/libgrabbag.la \
$(top_builddir)/src/share/getopt/libgetopt.la \
$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
$(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
$(top_builddir)/src/libFLAC/libFLAC.la \
@LTLIBICONV@ \
-lm
flac_libs = \
$(top_builddir)/src/libFLAC/libFLAC-static.la \
$(top_builddir)/src/libFLAC++/libFLAC++-static.la \
@OGG_LIBS@ \
-lm
flac_SOURCES = \
${top_builddir}/src/flac/analyze.c \
${top_builddir}/src/flac/decode.c \
${top_builddir}/src/flac/encode.c \
${top_builddir}/src/flac/foreign_metadata.c \
${top_builddir}/src/flac/local_string_utils.c \
${top_builddir}/src/flac/utils.c \
${top_builddir}/src/flac/vorbiscomment.c \
${top_builddir}/src/flac/analyze.h \
${top_builddir}/src/flac/decode.h \
${top_builddir}/src/flac/encode.h \
${top_builddir}/src/flac/foreign_metadata.h \
${top_builddir}/src/flac/local_string_utils.h \
${top_builddir}/src/flac/utils.h \
${top_builddir}/src/flac/vorbiscomment.h
metaflac_SOURCES = \
${top_builddir}/src/metaflac/operations.c \
${top_builddir}/src/metaflac/operations_shorthand_cuesheet.c \
${top_builddir}/src/metaflac/operations_shorthand_picture.c \
${top_builddir}/src/metaflac/operations_shorthand_seektable.c \
${top_builddir}/src/metaflac/operations_shorthand_streaminfo.c \
${top_builddir}/src/metaflac/operations_shorthand_vorbiscomment.c \
${top_builddir}/src/metaflac/options.c \
${top_builddir}/src/metaflac/usage.c \
${top_builddir}/src/metaflac/utils.c \
${top_builddir}/src/metaflac/operations.h \
${top_builddir}/src/metaflac/operations_shorthand.h \
${top_builddir}/src/metaflac/options.h \
${top_builddir}/src/metaflac/usage.h \
${top_builddir}/src/metaflac/utils.h
+13
View File
@@ -0,0 +1,13 @@
Fuzzers fuzzer_decoder.cc and fuzzer_encoder.cc were taken from
https://github.com/guidovranken/flac-fuzzers
The header files in the directory fuzzing and below were taken from:
https://github.com/guidovranken/fuzzing-headers.git
Some minor modifications were made to make them build with the default C++
warning flags.
The code mentioned above, contributed by Guido Vranken, is licensed under
the MIT license. See the files themselves for details
+2
View File
@@ -0,0 +1,2 @@
extern int alloc_check_threshold, alloc_check_counter;
int alloc_check_threshold = INT32_MAX, alloc_check_counter = 0;
+408
View File
@@ -0,0 +1,408 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <fuzzing/datasource/datasource.hpp>
#include <fuzzing/memory.hpp>
#include "FLAC++/decoder.h"
#include "FLAC++/metadata.h"
#include "common.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 {
Metadata::Prototype * cloned_object = nullptr;
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);
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
cloned_object = new Metadata::StreamInfo(metadata);
else if (metadata->type == FLAC__METADATA_TYPE_PADDING)
cloned_object = new Metadata::Padding(metadata);
else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION)
cloned_object = new Metadata::Application(metadata);
else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE)
cloned_object = new Metadata::SeekTable(metadata);
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
cloned_object = new Metadata::VorbisComment(metadata);
else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET)
cloned_object = new Metadata::CueSheet(metadata);
else if (metadata->type == FLAC__METADATA_TYPE_PICTURE)
cloned_object = new Metadata::Picture(metadata);
else
return;
if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) {
if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE)
dynamic_cast<Metadata::SeekTable *>(cloned_object)->is_legal();
if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE)
dynamic_cast<Metadata::Picture *>(cloned_object)->is_legal(NULL);
if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET)
dynamic_cast<Metadata::CueSheet *>(cloned_object)->is_legal(true,NULL);
}
delete cloned_object;
}
::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);
bool use_ogg = true;
try {
if ( ds.Get<bool>() ) {
use_ogg = false;
}
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();
}
{
::FLAC__StreamDecoderInitStatus ret;
if ( !use_ogg ) {
ret = decoder.init();
} else {
ret = decoder.init_ogg();
}
if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
goto end;
}
}
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;
}
View File
+257
View File
@@ -0,0 +1,257 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <limits>
#include <fuzzing/datasource/datasource.hpp>
#include <fuzzing/memory.hpp>
#include "FLAC++/encoder.h"
#include "common.h"
namespace FLAC {
namespace Encoder {
class FuzzerStream : public Stream {
private:
// fuzzing::datasource::Datasource& ds;
public:
FuzzerStream(fuzzing::datasource::Datasource&) :
Stream() { }
::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override {
fuzzing::memory::memory_test(buffer, bytes);
#if 0
try {
if ( ds.Get<bool>() == true ) {
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
} catch ( ... ) { }
#endif
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
};
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzzing::datasource::Datasource ds(data, size);
FLAC::Encoder::FuzzerStream encoder(ds);
try {
const int channels = ds.Get<uint8_t>();
const int bps = ds.Get<uint8_t>();
encoder.set_channels(channels);
encoder.set_bits_per_sample(bps);
{
const bool res = encoder.set_streamable_subset(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_ogg_serial_number(ds.Get<long>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_verify(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_compression_level(ds.Get<uint8_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_do_exhaustive_model_search(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const auto s = ds.Get<std::string>();
const bool res = encoder.set_apodization(s.data());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_do_qlp_coeff_prec_search(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_do_escape_coding(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_rice_parameter_search_dist(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_blocksize(ds.Get<uint16_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_sample_rate(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
if ( size > 2 * 65535 * 4 ) {
/* With large inputs and expensive options enabled, the fuzzer can get *really* slow.
* Some combinations can make the fuzzer timeout (>60 seconds). However, while combining
* options makes the fuzzer slower, most options do not expose new code when combined.
* Therefore, combining slow options is disabled for large inputs. Any input containing
* more than 65536 * 2 samples of 32 bits each (max blocksize, stereo) is considered large
*/
encoder.set_do_qlp_coeff_prec_search(false);
encoder.set_do_exhaustive_model_search(false);
}
if ( size > 2 * 4096 * 4 + 250 ) {
/* With subdivide_tukey in the mix testing apodizations can get really expensive. Therefore
* this is disabled for inputs of more than one whole stereo block of 32-bit inputs plus a
* bit of overhead */
encoder.set_apodization("");
}
{
::FLAC__StreamEncoderInitStatus ret;
if ( ds.Get<bool>() ) {
ret = encoder.init();
} else {
ret = encoder.init_ogg();
}
if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) {
goto end;
}
}
/* These sets must fail, because encoder is already initialized */
{
bool res = false;
res = res || encoder.set_streamable_subset(true);
res = res || encoder.set_ogg_serial_number(0);
res = res || encoder.set_verify(true);
res = res || encoder.set_compression_level(0);
res = res || encoder.set_do_exhaustive_model_search(true);
res = res || encoder.set_do_mid_side_stereo(true);
res = res || encoder.set_loose_mid_side_stereo(true);
res = res || encoder.set_apodization("test");
res = res || encoder.set_max_lpc_order(0);
res = res || encoder.set_qlp_coeff_precision(0);
res = res || encoder.set_do_qlp_coeff_prec_search(true);
res = res || encoder.set_do_escape_coding(true);
res = res || encoder.set_min_residual_partition_order(0);
res = res || encoder.set_max_residual_partition_order(0);
res = res || encoder.set_rice_parameter_search_dist(0);
res = res || encoder.set_total_samples_estimate(0);
res = res || encoder.set_channels(channels);
res = res || encoder.set_bits_per_sample(16);
res = res || encoder.set_limit_min_bitrate(true);
res = res || encoder.set_blocksize(3021);
res = res || encoder.set_sample_rate(44100);
fuzzing::memory::memory_test(res);
if(res)
abort();
}
{
/* XORing values as otherwise compiler will optimize, apparently */
bool res = false;
res = res != encoder.get_streamable_subset();
res = res != encoder.get_verify();
res = res != encoder.get_do_exhaustive_model_search();
res = res != encoder.get_do_mid_side_stereo();
res = res != encoder.get_loose_mid_side_stereo();
res = res != encoder.get_max_lpc_order();
res = res != encoder.get_qlp_coeff_precision();
res = res != encoder.get_do_qlp_coeff_prec_search();
res = res != encoder.get_do_escape_coding();
res = res != encoder.get_min_residual_partition_order();
res = res != encoder.get_max_residual_partition_order();
res = res != encoder.get_rice_parameter_search_dist();
res = res != encoder.get_total_samples_estimate();
res = res != encoder.get_channels();
res = res != encoder.get_bits_per_sample();
res = res != encoder.get_limit_min_bitrate();
res = res != encoder.get_blocksize();
res = res != encoder.get_sample_rate();
fuzzing::memory::memory_test(res);
}
while ( ds.Get<bool>() ) {
{
auto dat = ds.GetVector<FLAC__int32>();
if( ds.Get<bool>() )
/* Mask */
for (size_t i = 0; i < dat.size(); i++)
/* If we get here, bps is 4 or larger, or init will have failed */
dat[i] = (int32_t)(((uint32_t)(dat[i]) << (32-bps)) >> (32-bps));
const uint32_t samples = dat.size() / channels;
if ( samples > 0 ) {
const int32_t* ptr = dat.data();
const bool res = encoder.process_interleaved(ptr, samples);
fuzzing::memory::memory_test(res);
}
}
}
} catch ( ... ) { }
end:
{
const bool res = encoder.finish();
fuzzing::memory::memory_test(res);
}
return 0;
}
+352
View File
@@ -0,0 +1,352 @@
/* fuzzer_encoder_v2
* Copyright (C) 2022-2023 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdlib>
#include <cstring> /* for memcpy */
#include "FLAC/stream_encoder.h"
#include "FLAC/metadata.h"
extern "C" {
#include "share/private.h"
}
#include "common.h"
/* This C++ fuzzer uses the FLAC and not FLAC++ because the latter lacks a few
* hidden functions like FLAC__stream_encoder_disable_constant_subframes. It
* is still processed by a C++ compiler because that's what oss-fuzz expects */
static FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
{
(void)encoder, (void)buffer, (void)bytes, (void)samples, (void)current_frame, (void)client_data;
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
FLAC__bool encoder_valid = true;
FLAC__StreamEncoder *encoder = 0;
FLAC__StreamEncoderState state;
FLAC__StreamMetadata *metadata[16] = {NULL};
unsigned num_metadata = 0;
FLAC__StreamMetadata_VorbisComment_Entry VorbisCommentField;
unsigned sample_rate, channels, bps;
uint64_t samples_estimate, samples_in_input;
unsigned compression_level, input_data_width, blocksize, max_lpc_order, qlp_coeff_precision, min_residual_partition_order, max_residual_partition_order, metadata_mask, instruction_set_disable_mask;
FLAC__bool ogg, write_to_file, interleaved;
FLAC__bool data_bools[24];
/* Set alloc threshold. This check was added later and no spare config
* bytes were left, so we're reusing the sample rate as that of little
* consequence to the encoder and decoder except reading the frame header */
if(size < 3)
return 0;
alloc_check_threshold = data[2];
alloc_check_counter = 0;
/* allocate the encoder */
if((encoder = FLAC__stream_encoder_new()) == NULL) {
fprintf(stderr, "ERROR: allocating encoder\n");
return 1;
}
/* Use first 20 byte for configuration */
if(size < 20){
FLAC__stream_encoder_delete(encoder);
return 0;
}
/* First 3 byte for sample rate, 4th byte for channels, 5th byte for bps */
sample_rate = ((unsigned)data[0] << 16) + ((unsigned)data[1] << 8) + data[2];
channels = data[3];
bps = data[4];
/* Number of samples estimate, format accepts 36-bit max */
samples_estimate = ((uint64_t)data[5] << 32) + ((unsigned)data[6] << 24) + ((unsigned)data[7] << 16) + ((unsigned)data[8] << 8) + data[9];
compression_level = data[10]&0b1111;
input_data_width = 1 + (data[10]>>4)%4;
samples_in_input = (size-20)/input_data_width;
blocksize = ((unsigned)data[11] << 8) + (unsigned)data[12];
max_lpc_order = data[13];
qlp_coeff_precision = data[14];
min_residual_partition_order = data[15] & 0b1111;
max_residual_partition_order = data[15] & 0b11110000;
metadata_mask = data[16];
instruction_set_disable_mask = data[17];
/* Get array of bools from configuration */
for(int i = 0; i < 16; i++)
data_bools[i] = data[18+i/8] & (1 << (i % 8));
ogg = data_bools[0];
interleaved = data_bools[1];
write_to_file = data_bools[13];
/* Set input and process parameters */
encoder_valid &= FLAC__stream_encoder_set_verify(encoder, data_bools[2]);
encoder_valid &= FLAC__stream_encoder_set_channels(encoder, channels);
encoder_valid &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
encoder_valid &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
encoder_valid &= FLAC__stream_encoder_set_total_samples_estimate(encoder, samples_estimate);
encoder_valid &= FLAC__stream_encoder_disable_instruction_set(encoder, instruction_set_disable_mask);
encoder_valid &= FLAC__stream_encoder_set_limit_min_bitrate(encoder, data_bools[15]);
/* Set compression related parameters */
encoder_valid &= FLAC__stream_encoder_set_compression_level(encoder, compression_level);
if(data_bools[3]){
/* Bias towards regular compression levels */
encoder_valid &= FLAC__stream_encoder_set_blocksize(encoder, blocksize);
encoder_valid &= FLAC__stream_encoder_set_max_lpc_order(encoder, max_lpc_order);
encoder_valid &= FLAC__stream_encoder_set_qlp_coeff_precision(encoder, qlp_coeff_precision);
encoder_valid &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, min_residual_partition_order);
/* With large inputs and expensive options enabled, the fuzzer can get *really* slow.
* Some combinations can make the fuzzer timeout (>60 seconds). However, while combining
* options makes the fuzzer slower, most options do not expose new code when combined.
* Therefore, combining slow options is disabled for large inputs. Any input containing
* more than 65536 * 2 samples (max blocksize, stereo) is considered large
*/
if(samples_in_input < (2*65536)) {
encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, data_bools[4]);
encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, data_bools[5]);
encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, data_bools[6]);
encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, data_bools[7]);
/* Combining model search, precision search and a high residual partition order is especially
* expensive, so limit that even further. This high partition order can only be set on
* large blocksize and with streamable subset disabled */
if(samples_in_input < (2 * 4609) || data_bools[4] || !data_bools[7] || !data_bools[5] || max_residual_partition_order < 9 || blocksize < 4609)
encoder_valid &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, max_residual_partition_order);
}
else {
if(!data_bools[4])
encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, false);
else if(data_bools[6])
encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, true);
else if(data_bools[7])
encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, true);
else if(data_bools[5])
encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, true);
}
encoder_valid &= FLAC__stream_encoder_set_do_mid_side_stereo(encoder, data_bools[8]);
encoder_valid &= FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, data_bools[9]);
encoder_valid &= FLAC__stream_encoder_disable_constant_subframes(encoder, data_bools[10]);
encoder_valid &= FLAC__stream_encoder_disable_fixed_subframes(encoder, data_bools[11]);
encoder_valid &= FLAC__stream_encoder_disable_verbatim_subframes(encoder, data_bools[12]);
}
/* Disable alloc check if requested */
if(encoder_valid && data_bools[14])
alloc_check_threshold = INT32_MAX;
/* add metadata */
if(encoder_valid && (metadata_mask & 1)) {
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO)) == NULL)
encoder_valid = false;
else
num_metadata++;
}
if(encoder_valid && (metadata_mask & 2) && size > 21){
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL)
encoder_valid = false;
else {
metadata[num_metadata++]->length = (((unsigned)data[20]) << 8) + (unsigned)(data[21]);
}
}
if(encoder_valid && (metadata_mask & 4) && size > 20){
FLAC__byte * application_data = (FLAC__byte *)malloc(size-20);
if(0 != application_data && ((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)) == NULL))
encoder_valid = false;
else {
memcpy(application_data,data+20,size-20);
FLAC__metadata_object_application_set_data(metadata[num_metadata++], application_data, size-20, 0);
}
}
if(encoder_valid && (metadata_mask & 8) && size > 25){
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE)) == NULL)
encoder_valid = false;
else {
unsigned seekpoint_spacing = ((unsigned)data[22] << 8) + data[23];
unsigned total_samples_for_seekpoints = ((unsigned)data[24] << 8) + data[25];
FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(metadata[num_metadata++], seekpoint_spacing, total_samples_for_seekpoints);
}
}
if(encoder_valid && (metadata_mask & 16)){
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) != NULL) {
bool vorbiscomment_valid = true;
/* Append a vorbis comment */
if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Nothing to 🤔 report"))
vorbiscomment_valid = false;
else {
if(FLAC__metadata_object_vorbiscomment_append_comment(metadata[num_metadata], VorbisCommentField, false)) {
/* Insert a vorbis comment at the first index */
if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Still nothing to report 🤔🤣"))
vorbiscomment_valid = false;
else
if(!FLAC__metadata_object_vorbiscomment_insert_comment(metadata[num_metadata], 0, VorbisCommentField, false)) {
free(VorbisCommentField.entry);
vorbiscomment_valid = false;
}
}
else {
free(VorbisCommentField.entry);
vorbiscomment_valid = false;
}
}
if(!vorbiscomment_valid) {
FLAC__metadata_object_delete(metadata[num_metadata]);
metadata[num_metadata] = 0;
}
else
num_metadata++;
}
}
if(encoder_valid && (metadata_mask & 32)){
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)) != NULL) {
if(!FLAC__metadata_object_cuesheet_insert_blank_track(metadata[num_metadata],0)) {
FLAC__metadata_object_delete(metadata[num_metadata]);
metadata[num_metadata] = 0;
}
else {
if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(metadata[num_metadata],0,0)) {
FLAC__metadata_object_delete(metadata[num_metadata]);
metadata[num_metadata] = 0;
}
else {
metadata[num_metadata]->data.cue_sheet.tracks[0].number = 1;
num_metadata++;
}
}
}
}
if(encoder_valid && (metadata_mask & 64)){
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) != NULL) {
num_metadata++;
}
}
if(encoder_valid && (metadata_mask & 128)){
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_UNDEFINED)) != NULL) {
metadata[num_metadata]->length = 24;
metadata[num_metadata]->data.unknown.data = (FLAC__byte *)calloc(24, 1);
num_metadata++;
}
}
if(num_metadata && encoder_valid)
encoder_valid = FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata);
/* initialize encoder */
if(encoder_valid) {
FLAC__StreamEncoderInitStatus init_status;
if(ogg)
if(write_to_file)
init_status = FLAC__stream_encoder_init_ogg_file(encoder, "/tmp/tmp.flac", NULL, NULL);
else
init_status = FLAC__stream_encoder_init_ogg_stream(encoder, NULL, write_callback, NULL, NULL, NULL, NULL);
else
if(write_to_file)
init_status = FLAC__stream_encoder_init_file(encoder, "/tmp/tmp.flac", NULL, NULL);
else
init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, NULL);
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
encoder_valid = false;
}
}
/* send samples to encoder */
if(encoder_valid && size > (input_data_width*channels+26)) {
unsigned samples = (size - 26)/input_data_width/channels;
const uint8_t * pcm_data = data + 26;
int32_t * data_as_int32 = (int32_t *)malloc(4*samples*channels);
if(0 != data_as_int32){
for(unsigned i = 0; i < samples*channels; i++)
if(input_data_width == 1)
data_as_int32[i] = (int32_t)pcm_data[i] - 0x80;
else if(input_data_width == 2)
data_as_int32[i] = (((int32_t)pcm_data[i*2] << 8) + pcm_data[i*2+1]) - 0x8000;
else if(input_data_width == 3)
data_as_int32[i] = (((int32_t)pcm_data[i*3] << 16) + ((int32_t)pcm_data[i*3+1] << 8) + pcm_data[i*3+2]) - 0x800000;
else if(input_data_width == 4)
data_as_int32[i] = (((int64_t)pcm_data[i*4] << 24) + ((int32_t)pcm_data[i*4+1] << 16) + ((int32_t)pcm_data[i*4+2] << 8) + pcm_data[i*4+3]) - 0x80000000;
/* feed samples to encoder */
if(interleaved)
encoder_valid = FLAC__stream_encoder_process_interleaved(encoder, data_as_int32, samples);
else {
encoder_valid = FLAC__stream_encoder_process(encoder, (const int32_t*[]){data_as_int32,
data_as_int32+samples,
data_as_int32+samples*2,
data_as_int32+samples*3,
data_as_int32+samples*4, data_as_int32+samples*5, data_as_int32+samples*6, data_as_int32+samples*7}, samples);
}
free(data_as_int32);
}
else {
encoder_valid = false;
}
}
state = FLAC__stream_encoder_get_state(encoder);
if(!(state == FLAC__STREAM_ENCODER_OK ||
state == FLAC__STREAM_ENCODER_UNINITIALIZED ||
state == FLAC__STREAM_ENCODER_CLIENT_ERROR ||
((state == FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR ||
state == FLAC__STREAM_ENCODER_FRAMING_ERROR ||
(state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR &&
FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR)) &&
alloc_check_threshold < INT32_MAX))) {
fprintf(stderr,"-----\nERROR: stream encoder returned %s\n-----\n",FLAC__stream_encoder_get_resolved_state_string(encoder));
if(state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) {
uint32_t frame_number, channel, sample_number;
FLAC__int32 expected, got;
FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, NULL, &frame_number, &channel, &sample_number, &expected, &got);
fprintf(stderr,"Frame number %d\nChannel %d\n Sample number %d\nExpected value %d\nGot %d\n", frame_number, channel, sample_number, expected, got);
}
abort();
}
FLAC__stream_encoder_finish(encoder);
/* now that encoding is finished, the metadata can be freed */
for(unsigned i = 0; i < 16; i++)
if(0 != metadata[i])
FLAC__metadata_object_delete(metadata[i]);
FLAC__stream_encoder_delete(encoder);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
flac_stream_marker="fLaC"
ogg_stream_marker="OggS"
flac_in_ogg_marker="\x7fFLAC"
synccode_fixed_blocksize="\xFF\xF8"
synccode_variable_blocksize="\xFF\xF9"
+18
View File
@@ -0,0 +1,18 @@
"bartlett"
"bartlett_hann"
"blackman"
"blackman_harris_4term_92db"
"connes"
"flattop"
"gauss()"
"hamming"
"hann"
"kaiser_bessel"
"nuttall"
"rectangle"
"triangle"
"tukey(0)"
"partial_tukey(0)"
"punchout_tukey(0)"
"subdivide_tukey(0)"
"welch"
+6
View File
@@ -0,0 +1,6 @@
flac_stream_marker="fLaC"
ogg_stream_marker="OggS"
flac_in_ogg_marker="\x7fFLAC"
synccode_fixed_blocksize="\xFF\xF8"
synccode_variable_blocksize="\xFF\xF9"
+19
View File
@@ -0,0 +1,19 @@
"--keep-foreign-metadata-if-present"
"--replay-gain"
"--apply-replaygain-which-is-not-lossless"
"--force-raw-format"
"--force-aiff-format"
"--force-rf64-format"
"--force-wave64-format"
"--force-aiff-c-sowt-format"
"--force-aiff-c-none-format"
"--force-legacy-wave-format"
"--force-extensible-wave-format"
"--endian=big"
"--sample-rate=1"
"--channels=1"
"--bps=32"
"--sign=unsigned"
+190
View File
@@ -0,0 +1,190 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <fuzzing/exception.hpp>
#include <fuzzing/types.hpp>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
namespace fuzzing {
namespace datasource {
class Base
{
protected:
virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
public:
Base(void) = default;
virtual ~Base(void) = default;
template<class T> T Get(const uint64_t id = 0);
uint16_t GetChoice(const uint64_t id = 0);
std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
template <class T> std::vector<T> GetVector(const uint64_t id = 0);
class OutOfData : public fuzzing::exception::FlowException {
public:
OutOfData() = default;
};
class DeserializationFailure : public fuzzing::exception::FlowException {
public:
DeserializationFailure() = default;
};
};
#ifndef FUZZING_HEADERS_NO_IMPL
template<class T> T Base::Get(const uint64_t id)
{
T ret;
const auto v = get(sizeof(ret), sizeof(ret), id);
memcpy(&ret, v.data(), sizeof(ret));
return ret;
}
template <> bool Base::Get<bool>(const uint64_t id)
{
uint8_t ret;
const auto v = get(sizeof(ret), sizeof(ret), id);
memcpy(&ret, v.data(), sizeof(ret));
return (ret % 2) ? true : false;
}
template <> std::string Base::Get<std::string>(const uint64_t id)
{
auto data = GetData(id);
return std::string(data.data(), data.data() + data.size());
}
template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
{
std::vector<std::string> ret;
while ( true ) {
auto data = GetData(id);
ret.push_back( std::string(data.data(), data.data() + data.size()) );
if ( Get<bool>(id) == false ) {
break;
}
}
return ret;
}
uint16_t Base::GetChoice(const uint64_t id)
{
return Get<uint16_t>(id);
}
std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
{
return get(min, max, id);
}
template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
const auto data = GetData(id);
types::String<> ret(data.data(), data.size());
return ret;
}
template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
const auto data = GetData(id);
types::Data<> ret(data.data(), data.size());
return ret;
}
template <class T>
std::vector<T> Base::GetVector(const uint64_t id) {
std::vector<T> ret;
while ( Get<bool>(id) == true ) {
ret.push_back( Get<T>(id) );
}
return ret;
}
#endif
class Datasource : public Base
{
private:
const uint8_t* data;
const size_t size;
size_t idx;
size_t left;
std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;
// Make copy constructor and assignment operator private.
Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
Datasource& operator=(const Datasource &) { return *this; }
public:
Datasource(const uint8_t* _data, const size_t _size);
};
#ifndef FUZZING_HEADERS_NO_IMPL
Datasource::Datasource(const uint8_t* _data, const size_t _size) :
Base(), data(_data), size(_size), idx(0), left(size)
{
}
std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
(void)id;
uint32_t getSize;
if ( left < sizeof(getSize) ) {
throw OutOfData();
}
memcpy(&getSize, data + idx, sizeof(getSize));
idx += sizeof(getSize);
left -= sizeof(getSize);
if ( getSize < min ) {
getSize = min;
}
if ( max && getSize > max ) {
getSize = max;
}
if ( left < getSize ) {
throw OutOfData();
}
std::vector<uint8_t> ret(getSize);
if ( getSize > 0 ) {
memcpy(ret.data(), data + idx, getSize);
}
idx += getSize;
left -= getSize;
return ret;
}
#endif
} /* namespace datasource */
} /* namespace fuzzing */
+75
View File
@@ -0,0 +1,75 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <utility>
#include <map>
namespace fuzzing {
namespace datasource {
/* From: https://gist.github.com/underscorediscovery/81308642d0325fd386237cfa3b44785c */
inline uint64_t hash_64_fnv1a(const void* key, const uint64_t len) {
const char* data = (char*)key;
uint64_t hash = 0xcbf29ce484222325;
uint64_t prime = 0x100000001b3;
for(uint64_t i = 0; i < len; ++i) {
uint8_t value = data[i];
hash = hash ^ value;
hash *= prime;
}
return hash;
} //hash_64_fnv1a
// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit
// str should be a null terminated string literal, value should be left out
// e.g hash_32_fnv1a_const("example")
// code license: public domain or equivalent
// post: https://notes.underscorediscovery.com/constexpr-fnv1a/
constexpr uint32_t val_32_const = 0x811c9dc5;
constexpr uint32_t prime_32_const = 0x1000193;
constexpr uint64_t val_64_const = 0xcbf29ce484222325;
constexpr uint64_t prime_64_const = 0x100000001b3;
inline constexpr uint64_t ID(const char* const str, const uint64_t value = val_64_const) noexcept {
auto ret = (str[0] == '\0') ? value : ID(&str[1], (value ^ uint64_t(str[0])) * prime_64_const);
return ret;
}
inline constexpr std::pair<const char*, uint64_t> IDPair(const char* const str, const uint64_t value = val_64_const) noexcept {
return {str, ID(str, value)};
}
using IDMap = std::map<const char*, uint64_t>;
} /* namespace datasource */
} /* namespace fuzzing */
+67
View File
@@ -0,0 +1,67 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <exception>
#include <string>
namespace fuzzing {
namespace exception {
class ExceptionBase : public std::exception {
public:
ExceptionBase(void) = default;
/* typeid(T).name */
};
/* Recoverable exception */
class FlowException : public ExceptionBase {
public:
FlowException(void) : ExceptionBase() { }
};
/* Error in this library, should never happen */
class LogicException : public ExceptionBase {
private:
std::string reason;
public:
LogicException(const std::string r) : ExceptionBase(), reason(r) { }
virtual const char* what(void) const throw() {
return reason.c_str();
}
};
/* Error in target application */
class TargetException : public ExceptionBase {
private:
std::string reason;
public:
TargetException(const std::string r) : ExceptionBase(), reason(r) { }
virtual const char* what(void) const throw() {
return reason.c_str();
}
};
} /* namespace exception */
} /* namespace fuzzing */
+96
View File
@@ -0,0 +1,96 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <stdio.h>
#include <optional>
#ifndef ASAN
#define ASAN 0
#endif
#ifndef MSAN
#define MSAN 0
#endif
namespace fuzzing {
namespace memory {
#ifndef FUZZING_HEADERS_NO_IMPL
#if ASAN == 1
extern "C" void *__asan_region_is_poisoned(const void *beg, size_t size);
#endif
#if MSAN == 1
extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
#endif
void memory_test_asan(const void* data, const size_t size)
{
(void)data;
(void)size;
#if ASAN == 1
if ( __asan_region_is_poisoned(data, size) != NULL ) {
abort();
}
#endif
}
void memory_test_msan(const void* data, const size_t size)
{
(void)data;
(void)size;
#if MSAN == 1
__msan_check_mem_is_initialized(data, size);
#endif
}
void memory_test(const void* data, const size_t size)
{
memory_test_asan(data, size);
memory_test_msan(data, size);
}
template <class T>
void memory_test(const T& t)
{
(void)t;
}
template <>
void memory_test(const std::string& s)
{
(void)s;
#if MSAN == 1
memory_test(s.data(), s.size());
#endif
}
#endif
} /* namespace memory */
} /* namespace fuzzing */
+158
View File
@@ -0,0 +1,158 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fuzzing/memory.hpp>
#include <vector>
#include <string>
namespace fuzzing {
namespace types {
template <typename CoreType, bool NullTerminated, bool UseMSAN = false>
class Container {
private:
CoreType* InvalidAddress = (CoreType*)0x12;
CoreType* _data = InvalidAddress;
size_t _size = 0;
#ifndef FUZZING_HEADERS_NO_IMPL
void copy(const void* data, size_t size) {
if ( size > 0 ) {
std::memcpy(_data, data, size);
}
}
void allocate(size_t size) {
if ( size > 0 ) {
_data = static_cast<CoreType*>(malloc(size * sizeof(CoreType)));
} else {
_data = InvalidAddress;
}
};
void allocate_and_copy(const void* data, size_t size) {
allocate(size);
copy(data, size);
}
void allocate_plus_1_and_copy(const void* data, size_t size) {
allocate(size+1);
copy(data, size);
}
void access_hook(void) const {
if ( UseMSAN == true ) {
memory::memory_test_msan(_data, _size);
}
}
void free(void) {
access_hook();
if ( _data != InvalidAddress ) {
std::free(_data);
_data = InvalidAddress;
_size = 0;
}
}
#endif
public:
#ifndef FUZZING_HEADERS_NO_IMPL
CoreType* data(void) {
access_hook();
return _data;
}
size_t size(void) const {
access_hook();
return _size;
}
#endif
Container(void)
#ifndef FUZZING_HEADERS_NO_IMPL
= default
#endif
;
Container(const void* data, const size_t size)
#ifndef FUZZING_HEADERS_NO_IMPL
{
if ( NullTerminated == false ) {
allocate_and_copy(data, size);
} else {
allocate_plus_1_and_copy(data, size);
_data[size] = 0;
}
access_hook();
}
#endif
;
template<class T>
Container(const T& t)
#ifndef FUZZING_HEADERS_NO_IMPL
{
Container(t.data(), t.size());
}
#endif
;
~Container(void)
#ifndef FUZZING_HEADERS_NO_IMPL
{
this->free();
}
#endif
;
// The copy constructor was not originally explicitly supplied
// so it must have been incorrectly just copying the pointers.
Container(const Container &c) {
InvalidAddress = c.InvalidAddress;
allocate_and_copy(c._data, c._size);
}
Container& operator=(Container &c) {
InvalidAddress = c.InvalidAddress;
allocate_and_copy(c._data, c._size);
}
};
template <bool UseMSAN = false> using String = Container<char, true, UseMSAN>;
template <bool UseMSAN = false> using Data = Container<uint8_t, false, UseMSAN>;
} /* namespace types */
} /* namespace fuzzing */
+526
View File
@@ -0,0 +1,526 @@
/* fuzzer_metadata
* Copyright (C) 2022-2023 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdlib>
#include <cstdio>
#include <cstring> /* for memcpy */
#include <unistd.h>
#include "FLAC++/metadata.h"
#include "common.h"
#define CONFIG_LENGTH 2
#define min(x,y) (x<y?x:y)
static void run_tests_with_level_0_interface(char filename[]);
static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size);
static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
uint8_t command_length;
char filename[] = "/tmp/tmpXXXXXX.flac";
FLAC__bool init_bools[4];
/* Use first byte for configuration, leave at least one byte of input */
if(size < 1 + CONFIG_LENGTH){
return 0;
}
/* First 4 bits for configuration bools, next 4 for length of command section */
for(int i = 0; i < 4; i++)
init_bools[i] = data[i/8] & (1 << (i % 8));
command_length = data[0] >> 4;
if(0)//data[1] < 128) /* Use MSB as on/off */
alloc_check_threshold = data[1];
else
alloc_check_threshold = INT32_MAX;
alloc_check_counter = 0;
/* Leave at least one byte as input */
if(command_length >= size - 1 - CONFIG_LENGTH)
command_length = size - 1 - CONFIG_LENGTH;
/* Dump input to file */
{
int file_to_fuzz = mkstemps(filename, 5);
if (file_to_fuzz < 0)
abort();
write(file_to_fuzz,data+CONFIG_LENGTH+command_length,size-CONFIG_LENGTH-command_length);
close(file_to_fuzz);
}
run_tests_with_level_0_interface(filename);
run_tests_with_level_1_interface(filename, init_bools[1], init_bools[2], data+CONFIG_LENGTH, command_length/2);
/* Dump input to file, to start fresh for level 2 */
if(!init_bools[1]){
FILE * file_to_fuzz = fopen(filename,"w");
fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_fuzz);
fclose(file_to_fuzz);
}
run_tests_with_level_2_interface(filename, init_bools[0], init_bools[3], data+command_length/2+CONFIG_LENGTH, command_length/2);
remove(filename);
return 0;
}
static void run_tests_with_level_0_interface(char filename[]) {
FLAC::Metadata::StreamInfo streaminfo;
FLAC::Metadata::VorbisComment vorbis_comment;
FLAC::Metadata::CueSheet cue_sheet;
FLAC::Metadata::Picture picture;
FLAC::Metadata::get_streaminfo(filename,streaminfo);
FLAC::Metadata::get_tags(filename,vorbis_comment);
FLAC::Metadata::get_cuesheet(filename,cue_sheet);
FLAC::Metadata::get_picture(filename,picture, (FLAC__StreamMetadata_Picture_Type)(1), NULL, NULL, -1, -1, -1, -1);
}
static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size) {
FLAC::Metadata::SimpleIterator iterator;
FLAC::Metadata::Prototype *metadata_block = nullptr;
uint8_t id[4] = {0};
if(!iterator.is_valid())
return;
if(!iterator.init(filename,readonly,preservestats))
return;
for(size_t i = 0; i < size && iterator.status() == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; i++) {
switch(data[i] & 7) {
case 0:
iterator.get_block_type();
iterator.get_block_offset();
iterator.get_block_length();
iterator.get_application_id(id);
break;
case 1:
iterator.next();
break;
case 2:
iterator.prev();
break;
case 3:
iterator.delete_block(data[i] & 8);
break;
case 4:
if(metadata_block != 0) {
delete metadata_block;
metadata_block = nullptr;
}
metadata_block = iterator.get_block();
break;
case 5:
if(metadata_block != 0)
iterator.set_block(metadata_block,data[i] & 8);
break;
case 6:
if(metadata_block != 0)
iterator.insert_block_after(metadata_block, data[i] & 8);
break;
case 7:
iterator.status();
iterator.is_last();
iterator.is_writable();
break;
}
}
if(metadata_block != 0) {
delete metadata_block;
metadata_block = nullptr;
}
}
static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size) {
FLAC::Metadata::Chain chain;
FLAC::Metadata::Iterator iterator;
FLAC::Metadata::Prototype *metadata_block_get = nullptr;
FLAC::Metadata::Prototype *metadata_block_transfer = nullptr;
FLAC::Metadata::Prototype *metadata_block_put = nullptr;
if(!chain.is_valid())
return;
if(!chain.read(filename, ogg))
return;
iterator.init(chain);
for(size_t i = 0; i < size; i++) {
switch(data[i] & 15) {
case 0:
iterator.get_block_type();
break;
case 1:
iterator.next();
break;
case 2:
iterator.prev();
break;
case 3:
iterator.delete_block(data[i] & 16);
break;
case 4:
metadata_block_get = iterator.get_block();
if(metadata_block_get != 0 && metadata_block_get->is_valid()) {
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
if(metadata_block_transfer != metadata_block_get) {
delete metadata_block_transfer;
metadata_block_transfer = nullptr;
metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
}
}
else {
metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
}
}
delete metadata_block_get;
break;
case 5:
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
if(!iterator.insert_block_before(metadata_block_put))
delete metadata_block_put;
}
else
if(metadata_block_put != 0)
delete metadata_block_put;
}
break;
case 6:
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
if(!iterator.insert_block_after(metadata_block_put))
delete metadata_block_put;
}
else
if(metadata_block_put != 0)
delete metadata_block_put;
}
break;
case 7:
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
if(!iterator.set_block(metadata_block_put))
delete metadata_block_put;
}
else
if(metadata_block_put != 0)
delete metadata_block_put;
}
break;
case 8: /* Examine block */
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
switch(metadata_block_transfer->get_type()) {
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
uint32_t num_comments;
::FLAC__StreamMetadata_VorbisComment_Entry entry;
FLAC::Metadata::VorbisComment::Entry entry_cpp;
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
const ::FLAC__StreamMetadata * metadata_c = *metadata_block_transfer;
if(vorbiscomment == 0)
abort();
vorbiscomment->get_vendor_string();
num_comments = vorbiscomment->get_num_comments();
if(num_comments > 0) {
entry = metadata_c->data.vorbis_comment.comments[min(data[i]>>4,num_comments-1)];
if(entry.entry == 0)
abort();
if(vorbiscomment->get_comment(min(data[i]>>4,num_comments-1)).is_valid()) {
entry_cpp = vorbiscomment->get_comment(min(data[i]>>4,num_comments-1));
if(entry_cpp.is_valid() && entry_cpp.get_field() == 0)
abort();
vorbiscomment->find_entry_from(0,"TEST");
}
}
}
break;
case FLAC__METADATA_TYPE_CUESHEET:
{
uint32_t num_tracks, num_indices;
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
if(cuesheet == 0 || !cuesheet->is_legal())
break;
cuesheet->is_legal(true); /* check CDDA subset */
cuesheet->calculate_cddb_id();
cuesheet->get_media_catalog_number();
cuesheet->get_lead_in();
cuesheet->get_is_cd();
num_tracks = cuesheet->get_num_tracks();
if(num_tracks > 0) {
FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
track.get_offset();
track.get_number();
track.get_isrc();
track.get_pre_emphasis();
num_indices = track.get_num_indices();
if(num_indices > 0) {
FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
(void)index;
}
}
}
break;
case FLAC__METADATA_TYPE_PICTURE:
{
char * violation = nullptr;
FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
if(picture == 0 || !picture->is_legal((const char **)&violation))
break;
picture->get_data();
}
break;
default:
break;
}
}
break;
case 9: /* Replace or add in block */
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
switch(metadata_block_transfer->get_type()) {
case FLAC__METADATA_TYPE_SEEKTABLE:
{
uint32_t num_seekpoints;
FLAC__StreamMetadata_SeekPoint seekpoint;
FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
if(seektable == 0)
break;
if(seektable->is_valid() && seektable->is_legal()) {
num_seekpoints = seektable->get_num_points();
if(num_seekpoints > 0) {
seekpoint = seektable->get_point(min(data[i]>>5,num_seekpoints-1));
seektable->set_point(0,seekpoint);
seektable->insert_point(min(data[i]>>5,num_seekpoints-1),seekpoint);
}
seektable->template_append_placeholders(4);
seektable->template_append_point(111111);
seektable->template_append_points((FLAC__uint64[]){222222, 333333, 444444}, 3);
seektable->template_append_spaced_points(data[i]>>5, 1234567);
seektable->template_append_spaced_points_by_samples(data[i]>>5, 2468000);
seektable->template_sort(data[i] & 16);
}
}
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
uint32_t num_comments;
FLAC::Metadata::VorbisComment::Entry entry;
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
if(vorbiscomment == 0)
break;
num_comments = vorbiscomment->get_num_comments();
if(num_comments > 0 && entry.is_valid()) {
if(vorbiscomment->get_comment(min(data[i]>>5,num_comments-1)).is_valid()) {
entry = vorbiscomment->get_comment(min(data[i]>>5,num_comments-1));
if(entry.is_valid()) {
vorbiscomment->replace_comment(entry,data[i] & 16);
vorbiscomment->set_comment(0,entry);
vorbiscomment->append_comment(entry);
vorbiscomment->insert_comment(0,entry);
}
}
}
}
break;
case FLAC__METADATA_TYPE_CUESHEET:
{
uint32_t num_tracks, num_indices;
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
if(cuesheet == 0 || !cuesheet->is_legal())
break;
num_tracks = cuesheet->get_num_tracks();
if(num_tracks > 0) {
FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
num_indices = track.get_num_indices();
if(num_indices > 0) {
FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
track.set_index(0,index);
cuesheet->insert_index(0,0,index);
cuesheet->insert_blank_index(0,0);
}
cuesheet->insert_blank_track(0);
cuesheet->insert_track(0,track);
cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
}
}
break;
case FLAC__METADATA_TYPE_PICTURE:
{
FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
const char testtext[] = "TEST";
if(picture == 0 || !picture->is_legal(NULL))
break;
picture->set_description((FLAC__byte *)&testtext);
picture->set_mime_type((const char *)&testtext);
picture->set_data((FLAC__byte *)&testtext,4);
}
break;
default:
break;
}
}
break;
case 10: /* Delete from block */
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
switch(metadata_block_transfer->get_type()) {
case FLAC__METADATA_TYPE_SEEKTABLE:
{
uint32_t num_seekpoints;
FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
if(seektable == 0)
break;
if(seektable->is_valid() && seektable->is_legal()) {
num_seekpoints = seektable->get_num_points();
if(num_seekpoints > 0)
seektable->delete_point(min(data[i]>>4,num_seekpoints-1));
}
}
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
uint32_t num_comments;
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
if(vorbiscomment == 0)
break;
num_comments = vorbiscomment->get_num_comments();
if(num_comments > 0)
vorbiscomment->delete_comment(min(data[i]>>4,num_comments-1));
vorbiscomment->remove_entry_matching("TEST");
vorbiscomment->remove_entries_matching("TEST");
}
break;
case FLAC__METADATA_TYPE_CUESHEET:
{
uint32_t num_tracks;
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
if(cuesheet == 0 || !cuesheet->is_legal())
break;
num_tracks = cuesheet->get_num_tracks();
if(num_tracks > 0) {
FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
if(track.get_num_indices() > 0)
cuesheet->delete_index(min(data[i]>>4,num_tracks-1),0);
cuesheet->delete_track(0);
}
}
break;
default:
break;
}
}
break;
case 11: /* Resize block */
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
switch(metadata_block_transfer->get_type()) {
case FLAC__METADATA_TYPE_PADDING:
{
FLAC::Metadata::Padding * padding = dynamic_cast<FLAC::Metadata::Padding *>(metadata_block_transfer);
if(padding == 0)
break;
padding->set_length(data[i]>>4);
}
break;
case FLAC__METADATA_TYPE_SEEKTABLE:
{
FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
if(seektable == 0)
break;
seektable->resize_points(data[i]>>4);
}
break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
if(vorbiscomment == 0)
break;
vorbiscomment->resize_comments(data[i]>>4);
}
break;
case FLAC__METADATA_TYPE_CUESHEET:
{
uint32_t num_tracks;
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
if(cuesheet == 0 || !cuesheet->is_legal())
break;
num_tracks = cuesheet->get_num_tracks();
if(num_tracks > 0) {
cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
}
cuesheet->resize_tracks(data[i]<<4);
}
break;
default:
break;
}
}
break;
case 12: /* Prototype functions */
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
const ::FLAC__StreamMetadata * metadata_compare = *metadata_block_transfer;
metadata_block_transfer->get_is_last();
metadata_block_transfer->get_length();
metadata_block_transfer->set_is_last(data[i] & 16);
FLAC__metadata_object_is_equal(metadata_compare, metadata_compare);
}
break;
}
}
if(metadata_block_transfer != 0) {
delete metadata_block_transfer;
metadata_block_transfer = nullptr;
}
chain.status();
chain.sort_padding();
chain.merge_padding();
chain.check_if_tempfile_needed(!use_padding);
chain.write(use_padding);
}
+304
View File
@@ -0,0 +1,304 @@
/* Copyright 2019 Guido Vranken
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <limits>
#include <fuzzing/datasource/datasource.hpp>
#include <fuzzing/memory.hpp>
#include "FLAC++/encoder.h"
#include "FLAC++/decoder.h"
#include "FLAC++/metadata.h"
#include "common.h"
#define MAX_NUM_METADATA_BLOCKS 2048
namespace FLAC {
namespace Encoder {
class FuzzerStream : public Stream {
private:
// fuzzing::datasource::Datasource& ds;
public:
FuzzerStream(fuzzing::datasource::Datasource&) :
Stream() { }
::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override {
fuzzing::memory::memory_test(buffer, bytes);
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
};
}
namespace Decoder {
class FuzzerDecoder : public Stream {
private:
fuzzing::datasource::Datasource& ds;
FLAC::Encoder::FuzzerStream& encoder;
public:
FuzzerDecoder(fuzzing::datasource::Datasource& dsrc, FLAC::Encoder::FuzzerStream& encoder_arg) :
Stream(), ds(dsrc), encoder(encoder_arg) { }
::FLAC__StreamMetadata * metadata_blocks[MAX_NUM_METADATA_BLOCKS] = {0};
int num_metadata_blocks = 0;
void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
if(num_metadata_blocks < MAX_NUM_METADATA_BLOCKS)
if((metadata_blocks[num_metadata_blocks] = FLAC__metadata_object_clone(metadata)) != NULL)
num_metadata_blocks++;
}
::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);
}
}
/* Data is checked, now pass it towards encoder */
if(encoder.get_state() == FLAC__STREAM_ENCODER_OK) {
if(encoder.get_channels() != get_channels())
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
if(encoder.get_bits_per_sample() != get_bits_per_sample())
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
encoder.process(buffer, frame->header.blocksize);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
else
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
void error_callback(::FLAC__StreamDecoderErrorStatus status) override {
fuzzing::memory::memory_test(status);
}
};
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzzing::datasource::Datasource ds(data, size);
FLAC::Encoder::FuzzerStream encoder(ds);
FLAC::Decoder::FuzzerDecoder decoder(ds, encoder);
try {
const int channels = ds.Get<uint8_t>();
const int bps = ds.Get<uint8_t>();
encoder.set_channels(channels);
encoder.set_bits_per_sample(bps);
{
const bool res = encoder.set_streamable_subset(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_ogg_serial_number(ds.Get<long>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_verify(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_compression_level(ds.Get<uint8_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_do_escape_coding(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_blocksize(ds.Get<uint16_t>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>());
fuzzing::memory::memory_test(res);
}
{
const bool res = encoder.set_sample_rate(ds.Get<uint32_t>());
fuzzing::memory::memory_test(res);
}
decoder.set_metadata_respond_all();
{
::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;
}
decoder.process_until_end_of_metadata();
if(decoder.num_metadata_blocks > 0)
encoder.set_metadata(decoder.metadata_blocks, decoder.num_metadata_blocks);
}
{
::FLAC__StreamEncoderInitStatus ret;
if ( ds.Get<bool>() ) {
ret = encoder.init();
} else {
ret = encoder.init_ogg();
}
if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) {
goto end;
}
}
/* These sets must fail, because encoder is already initialized */
{
bool res = false;
res = res || encoder.set_streamable_subset(true);
res = res || encoder.set_ogg_serial_number(0);
res = res || encoder.set_verify(true);
res = res || encoder.set_compression_level(0);
res = res || encoder.set_do_exhaustive_model_search(true);
res = res || encoder.set_do_mid_side_stereo(true);
res = res || encoder.set_loose_mid_side_stereo(true);
res = res || encoder.set_apodization("test");
res = res || encoder.set_max_lpc_order(0);
res = res || encoder.set_qlp_coeff_precision(0);
res = res || encoder.set_do_qlp_coeff_prec_search(true);
res = res || encoder.set_do_escape_coding(true);
res = res || encoder.set_min_residual_partition_order(0);
res = res || encoder.set_max_residual_partition_order(0);
res = res || encoder.set_rice_parameter_search_dist(0);
res = res || encoder.set_total_samples_estimate(0);
res = res || encoder.set_channels(channels);
res = res || encoder.set_bits_per_sample(16);
res = res || encoder.set_limit_min_bitrate(true);
res = res || encoder.set_blocksize(3021);
res = res || encoder.set_sample_rate(44100);
fuzzing::memory::memory_test(res);
if(res)
abort();
}
{
/* XORing values as otherwise compiler will optimize, apparently */
bool res = false;
res = res != encoder.get_streamable_subset();
res = res != encoder.get_verify();
res = res != encoder.get_do_exhaustive_model_search();
res = res != encoder.get_do_mid_side_stereo();
res = res != encoder.get_loose_mid_side_stereo();
res = res != encoder.get_max_lpc_order();
res = res != encoder.get_qlp_coeff_precision();
res = res != encoder.get_do_qlp_coeff_prec_search();
res = res != encoder.get_do_escape_coding();
res = res != encoder.get_min_residual_partition_order();
res = res != encoder.get_max_residual_partition_order();
res = res != encoder.get_rice_parameter_search_dist();
res = res != encoder.get_total_samples_estimate();
res = res != encoder.get_channels();
res = res != encoder.get_bits_per_sample();
res = res != encoder.get_limit_min_bitrate();
res = res != encoder.get_blocksize();
res = res != encoder.get_sample_rate();
fuzzing::memory::memory_test(res);
}
decoder.process_until_end_of_stream();
} catch ( ... ) { }
end:
{
const bool res = encoder.finish();
fuzzing::memory::memory_test(res);
}
{
const bool res = decoder.finish();
fuzzing::memory::memory_test(res);
}
for(int i = 0; i < decoder.num_metadata_blocks; i++)
FLAC__metadata_object_delete(decoder.metadata_blocks[i]);
return 0;
}
+195
View File
@@ -0,0 +1,195 @@
/* fuzzer_seek
* Copyright (C) 2022-2023 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdlib>
#include <cstring> /* for memcpy */
#include "FLAC/stream_decoder.h"
#include "common.h"
int write_abort_check_counter = -1;
#if 0 /* set to 1 to debug */
#define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__)
#else
#define FPRINTF_DEBUG_ONLY(...)
#endif
#define CONFIG_LENGTH 2
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
{
(void)decoder, (void)frame, (void)buffer, (void)client_data;
if(write_abort_check_counter > 0) {
write_abort_check_counter--;
if(write_abort_check_counter == 0)
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
} else if(write_abort_check_counter == 0)
/* This must not happen: write callback called after abort is returned */
abort();
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus error, void *client_data)
{
(void)decoder, (void)error, (void)client_data;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
FLAC__bool decoder_valid = true;
FLAC__StreamDecoder *decoder;
uint8_t command_length;
FLAC__bool init_bools[16], ogg;
if(size > 2 && data[1] < 128) /* Use MSB as on/off */
alloc_check_threshold = data[1];
else
alloc_check_threshold = INT32_MAX;
alloc_check_counter = 0;
write_abort_check_counter = -1;
/* allocate the decoder */
if((decoder = FLAC__stream_decoder_new()) == NULL) {
fprintf(stderr, "ERROR: allocating decoder\n");
return 1;
}
/* Use first byte for configuration, leave at least one byte of input */
if(size < 1 + CONFIG_LENGTH){
FLAC__stream_decoder_delete(decoder);
return 0;
}
/* First 4 bits for configuration bools, next 4 for length of command section */
for(int i = 0; i < 4; i++)
init_bools[i] = data[i/8] & (1 << (i % 8));
command_length = data[0] >> 4;
/* Leave at least one byte as input */
if(command_length >= size - 1 - CONFIG_LENGTH)
command_length = size - 1 - CONFIG_LENGTH;
/* Dump decoder input to file */
{
FILE * file_to_decode = fopen("/tmp/tmp.flac","w");
fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_decode);
fclose(file_to_decode);
}
ogg = init_bools[0];
FLAC__stream_decoder_set_md5_checking(decoder,init_bools[1]);
if(init_bools[2])
FLAC__stream_decoder_set_metadata_respond_all(decoder);
if(init_bools[3])
FLAC__stream_decoder_set_metadata_ignore_all(decoder);
/* initialize decoder */
if(decoder_valid) {
FLAC__StreamDecoderInitStatus init_status;
if(ogg)
init_status = FLAC__stream_decoder_init_ogg_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL);
else
init_status = FLAC__stream_decoder_init_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL);
if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
decoder_valid = false;
}
}
/* Run commands */
for(uint8_t i = 0; decoder_valid && (i < command_length); i++){
const uint8_t * command = data+CONFIG_LENGTH+i;
uint8_t shift = 1u << (command[0] >> 3);
FLAC__uint64 seekpos;
switch(command[0] & 15){
case 0:
FPRINTF_DEBUG_ONLY(stderr,"end_of_stream\n");
decoder_valid = FLAC__stream_decoder_process_until_end_of_stream(decoder);
break;
case 1:
FPRINTF_DEBUG_ONLY(stderr,"end_of_metadata\n");
decoder_valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder);
break;
case 2:
FPRINTF_DEBUG_ONLY(stderr,"single\n");
decoder_valid = FLAC__stream_decoder_process_single(decoder);
break;
case 3:
FPRINTF_DEBUG_ONLY(stderr,"skip_single\n");
decoder_valid = FLAC__stream_decoder_skip_single_frame(decoder);
break;
case 4:
FPRINTF_DEBUG_ONLY(stderr,"reset\n");
decoder_valid = FLAC__stream_decoder_reset(decoder);
break;
case 5:
FPRINTF_DEBUG_ONLY(stderr,"flush\n");
decoder_valid = FLAC__stream_decoder_flush(decoder);
break;
case 6:
case 14:
shift = 1u << (command[0] >> 3);
FPRINTF_DEBUG_ONLY(stderr,"seek short %hhu\n",shift);
decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,shift);
break;
case 7:
if(i+8 >= command_length) /* Not enough data available to do this */
break;
seekpos = ((FLAC__uint64)command[1] << 56) +
((FLAC__uint64)command[2] << 48) +
((FLAC__uint64)command[3] << 40) +
((FLAC__uint64)command[4] << 32) +
((FLAC__uint64)command[5] << 24) +
((FLAC__uint64)command[6] << 16) +
((FLAC__uint64)command[7] << 8) +
command[8];
i+=8;
FPRINTF_DEBUG_ONLY(stderr,"seek long %lu\n",seekpos);
decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,seekpos);
break;
case 8:
/* Set abort on write callback */
write_abort_check_counter = (command[0] >> 4) + 1;
break;
}
}
FLAC__stream_decoder_finish(decoder);
FLAC__stream_decoder_delete(decoder);
return 0;
}
+117
View File
@@ -0,0 +1,117 @@
/* fuzzer_tool_flac
* Copyright (C) 2023 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h> /* for memcpy */
#define FUZZ_TOOL_FLAC
#define fprintf(...)
#define printf(...)
#include "../src/flac/main.c"
#include "common.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
size_t size_left = size;
size_t arglen;
char * argv[67];
char exename[] = "flac";
char filename[] = "/tmp/fuzzXXXXXX";
int numarg = 0, maxarg;
int file_to_fuzz;
int tmp_stdout, tmp_stdin;
fpos_t pos_stdout;
bool use_stdin = false;
/* reset global vars */
flac__utils_verbosity_ = 0;
share__opterr = 0;
share__optind = 0;
if(size < 2)
return 0;
maxarg = data[0] & 63;
use_stdin = data[0] & 64;
size_left--;
argv[0] = exename;
numarg++;
/* Check whether input is zero delimited */
while((arglen = strnlen((char *)data+(size-size_left),size_left)) < size_left && numarg < maxarg) {
argv[numarg++] = (char *)data+(size-size_left);
size_left -= arglen + 1;
}
file_to_fuzz = mkstemp(filename);
if (file_to_fuzz < 0)
abort();
write(file_to_fuzz,data+(size-size_left),size_left);
close(file_to_fuzz);
/* redirect stdout */
fflush(stdout);
fgetpos(stdout,&pos_stdout);
tmp_stdout = dup(fileno(stdout));
freopen("/dev/null","w",stdout);
/* redirect stdin */
tmp_stdin = dup(fileno(stdin));
if(use_stdin)
freopen(filename,"r",stdin);
else {
freopen("/dev/null","r",stdin);
argv[numarg++] = filename;
}
main_to_fuzz(numarg,argv);
/* restore stdout */
fflush(stdout);
dup2(tmp_stdout, fileno(stdout));
close(tmp_stdout);
clearerr(stdout);
fsetpos(stdout,&pos_stdout);
/* restore stdin */
dup2(tmp_stdin, fileno(stdin));
close(tmp_stdin);
clearerr(stdin);
unlink(filename);
return 0;
}
+136
View File
@@ -0,0 +1,136 @@
/* fuzzer_tool_flac
* Copyright (C) 2023 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for memcpy */
#define FUZZ_TOOL_METAFLAC
#define fprintf(...)
#define printf(...)
#include "../src/metaflac/main.c"
#include "common.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
size_t size_left = size;
size_t arglen;
char * argv[64];
char exename[] = "metaflac";
char filename[] = "/tmp/fuzzXXXXXX";
char filename_stdin[] = "/tmp/fuzzXXXXXX";
int numarg = 0, maxarg;
int file_to_fuzz;
int tmp_stdout, tmp_stdin;
fpos_t pos_stdout;
bool use_stdin = false;
share__opterr = 0;
share__optind = 0;
if(size < 2)
return 0;
maxarg = data[0] & 15;
use_stdin = data[0] & 16;
size_left--;
argv[0] = exename;
numarg++;
/* Check whether input is zero delimited */
while((arglen = strnlen((char *)data+(size-size_left),size_left)) < size_left && numarg < maxarg) {
argv[numarg++] = (char *)data+(size-size_left);
size_left -= arglen + 1;
}
/* Create file to feed directly */
file_to_fuzz = mkstemp(filename);
if (file_to_fuzz < 0)
abort();
if(use_stdin) {
write(file_to_fuzz,data+(size-size_left),size_left/2);
size_left -= size_left/2;
}
else
write(file_to_fuzz,data+(size-size_left),size_left);
close(file_to_fuzz);
argv[numarg++] = filename;
/* Create file to feed to stdin */
if(use_stdin) {
file_to_fuzz = mkstemp(filename_stdin);
if (file_to_fuzz < 0)
abort();
write(file_to_fuzz,data+(size-size_left),size_left);
close(file_to_fuzz);
}
/* redirect stdout */
fflush(stdout);
fgetpos(stdout,&pos_stdout);
tmp_stdout = dup(fileno(stdout));
freopen("/dev/null","w",stdout);
/* redirect stdin */
tmp_stdin = dup(fileno(stdin));
if(use_stdin)
freopen(filename_stdin,"r",stdin);
else {
freopen("/dev/null","r",stdin);
argv[numarg++] = filename;
}
main_to_fuzz(numarg,argv);
/* restore stdout */
fflush(stdout);
dup2(tmp_stdout, fileno(stdout));
close(tmp_stdout);
clearerr(stdout);
fsetpos(stdout,&pos_stdout);
/* restore stdin */
dup2(tmp_stdin, fileno(stdin));
close(tmp_stdin);
clearerr(stdin);
unlink(filename);
if(use_stdin)
unlink(filename_stdin);
return 0;
}