diff options
Diffstat (limited to 'oss-fuzz/seek.cc')
-rw-r--r-- | oss-fuzz/seek.cc | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/oss-fuzz/seek.cc b/oss-fuzz/seek.cc new file mode 100644 index 0000000..d3ccbe8 --- /dev/null +++ b/oss-fuzz/seek.cc @@ -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; +} + |