From c47beb15805485ab798b9cc2b63571b681869b79 Mon Sep 17 00:00:00 2001 From: Martijn van Beurden Date: Wed, 11 Dec 2024 06:41:28 +0100 Subject: [PATCH] Limit number of rewinds (#773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should reduce the number of timeouts. In case the decoder keeps rewinding, check 4 of the 8 CRC8 bits. If they match, keep rewinding. With this approach, the fuzzer doesn't get 'faster' then plain libFLAC, but fuzzing isn't affected too much by the CRC8 check. Time will tell whether the fuzzer finds an input triggering repeating rewinds, expensive processing ánd those 4 CRC8 bits check out. If it finds such an input, more CRC8 bits need to be checked. --- src/libFLAC/stream_decoder.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c index 09b6357e05..d8d36d1330 100644 --- a/src/libFLAC/stream_decoder.c +++ b/src/libFLAC/stream_decoder.c @@ -170,6 +170,9 @@ typedef struct FLAC__StreamDecoderPrivate { FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine and find_total_samples to check when process_single() actually writes a frame */ FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); FLAC__bool error_has_been_sent; /* To check whether a missing frame has been signalled yet */ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + uint32_t fuzzing_rewind_count; /* To stop excessive rewinding, as it causes timeouts */ +#endif } FLAC__StreamDecoderPrivate; /*********************************************************************** @@ -2511,6 +2514,9 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL decoder->private_->error_has_been_sent = false; if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC || decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + decoder->private_->fuzzing_rewind_count++; /* To stop excessive rewinding, as it causes timeouts */ +#endif /* Got corruption, rewind if possible. Return value of seek * isn't checked, if the seek fails the decoder will continue anyway */ if(!FLAC__bitreader_rewind_to_after_last_seen_framesync(decoder->private_->input)){ @@ -2542,6 +2548,9 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL } else { *got_a_frame = true; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + decoder->private_->fuzzing_rewind_count = 0; +#endif /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */ if(decoder->private_->next_fixed_block_size) @@ -2853,11 +2862,14 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if(FLAC__crc8(raw_header, raw_header_len) != crc8) { +#else + if(decoder->private_->fuzzing_rewind_count > 32 && (FLAC__crc8(raw_header, raw_header_len) << 4) != (crc8 << 4)) { +#endif + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } -#endif /* calculate the sample number from the frame number if needed */ decoder->private_->next_fixed_block_size = 0;