diff options
author | Martijn van Beurden <mvanb1@gmail.com> | 2022-06-08 13:39:23 +0200 |
---|---|---|
committer | Martijn van Beurden <mvanb1@gmail.com> | 2022-06-15 07:46:48 +0200 |
commit | 81c973fa1c0fd90edf5789c3c0573b4867799110 (patch) | |
tree | 609d688c5476e33ccd99cef9b7a0df6fc158e93b | |
parent | 78d85dd4e4e8044d0f6989182cd1a22a461dce37 (diff) | |
download | flac-81c973fa1c0fd90edf5789c3c0573b4867799110.tar.gz |
Add new decoder fuzzer, mostly to cover seeking
This second decoder fuzzer dumps the fuzz input to a file, which enables
testing of seeking code
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | oss-fuzz/Makefile.am | 8 | ||||
-rw-r--r-- | oss-fuzz/fuzzer_seek.cc | 172 |
3 files changed, 180 insertions, 1 deletions
@@ -77,6 +77,7 @@ test/picture.log microbench/benchmark_residual /ogg/ oss-fuzz/fuzzer_decoder +oss-fuzz/fuzzer_seek oss-fuzz/fuzzer_encoder oss-fuzz/fuzzer_encoder_v2 diff --git a/oss-fuzz/Makefile.am b/oss-fuzz/Makefile.am index c99dc85a..fecec44e 100644 --- a/oss-fuzz/Makefile.am +++ b/oss-fuzz/Makefile.am @@ -31,7 +31,7 @@ EXTRA_DIST = \ noinst_PROGRAMS = if USE_OSSFUZZERS -noinst_PROGRAMS += fuzzer_encoder fuzzer_encoder_v2 fuzzer_decoder +noinst_PROGRAMS += fuzzer_encoder fuzzer_encoder_v2 fuzzer_decoder fuzzer_seek endif fuzzer_encoder_SOURCES = fuzzer_encoder.cc @@ -49,6 +49,12 @@ fuzzer_decoder_CXXFLAGS = $(AM_CXXFLAGS) $(LIB_FUZZING_ENGINE) fuzzer_decoder_LDFLAGS = $(AM_LDFLAGS) fuzzer_decoder_LDADD = $(flac_libs) +fuzzer_seek_SOURCES = fuzzer_seek.cc +fuzzer_seek_CXXFLAGS = $(AM_CXXFLAGS) $(LIB_FUZZING_ENGINE) +fuzzer_seek_LDFLAGS = $(AM_LDFLAGS) +fuzzer_seek_LDADD = $(flac_libs) + + flac_libs = \ $(top_builddir)/src/libFLAC/libFLAC-static.la \ $(top_builddir)/src/libFLAC++/libFLAC++-static.la \ diff --git a/oss-fuzz/fuzzer_seek.cc b/oss-fuzz/fuzzer_seek.cc new file mode 100644 index 00000000..ed3df38e --- /dev/null +++ b/oss-fuzz/fuzzer_seek.cc @@ -0,0 +1,172 @@ +/* fuzzer_seek + * Copyright (C) 2022 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" + +#if 0 /* set to 1 to debug */ +#define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__) +#else +#define FPRINTF_DEBUG_ONLY(...) +#endif + +#define CONFIG_LENGTH 1 + +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; + 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; + + /* 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] & 7){ + 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: + 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; + } + } + + FLAC__stream_decoder_finish(decoder); + + FLAC__stream_decoder_delete(decoder); + + return 0; +} + |