diff options
author | Martijn van Beurden <mvanb1@gmail.com> | 2022-08-11 14:09:39 +0200 |
---|---|---|
committer | Martijn van Beurden <mvanb1@gmail.com> | 2022-08-20 16:03:53 +0200 |
commit | fbb6cb5c075d24ce35ccad6ca18f9cbbdb4e3d3f (patch) | |
tree | 567b3bf9467bf15dd99410b4c18c06fd69cec5c2 | |
parent | 707dace4bd82cd6042e524c72544ab50de223a10 (diff) | |
download | flac-fbb6cb5c075d24ce35ccad6ca18f9cbbdb4e3d3f.tar.gz |
Add OOM checking to fuzzing
-rw-r--r-- | include/share/alloc.h | 72 | ||||
-rw-r--r-- | oss-fuzz/fuzzer_decoder.cc | 1 | ||||
-rw-r--r-- | oss-fuzz/fuzzer_encoder.cc | 1 | ||||
-rw-r--r-- | oss-fuzz/fuzzer_encoder_v2.cc | 45 | ||||
-rw-r--r-- | oss-fuzz/fuzzer_metadata.cc | 10 | ||||
-rw-r--r-- | oss-fuzz/fuzzer_seek.cc | 10 |
6 files changed, 120 insertions, 19 deletions
diff --git a/include/share/alloc.h b/include/share/alloc.h index 74f444d6..0b40548e 100644 --- a/include/share/alloc.h +++ b/include/share/alloc.h @@ -63,19 +63,58 @@ # define SIZE_MAX SIZE_T_MAX #endif +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +extern int alloc_check_threshold, alloc_check_counter; + +static inline int alloc_check() { + if(alloc_check_threshold == INT32_MAX) + return 0; + else if(alloc_check_counter++ == alloc_check_threshold) + return 1; + else + return 0; +} + +#endif + /* avoid malloc()ing 0 bytes, see: * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 */ + static inline void *safe_malloc_(size_t size) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Fail if requested */ + if(alloc_check()) + return NULL; +#endif /* malloc(0) is undefined; FLAC src convention is to always allocate */ if(!size) size++; return malloc(size); } +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +static inline void *malloc_(size_t size) +{ + /* Fail if requested */ + if(alloc_check()) + return NULL; + return malloc(size); +} +#else +#define malloc_ malloc +#endif + + + static inline void *safe_calloc_(size_t nmemb, size_t size) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Fail if requested */ + if(alloc_check()) + return NULL; +#endif if(!nmemb || !size) return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ return calloc(nmemb, size); @@ -127,7 +166,7 @@ static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size size1 *= size2; if(size1 > SIZE_MAX / size3) return 0; - return malloc(size1*size3); + return malloc_(size1*size3); } /* size1*size2 + size3 */ @@ -150,23 +189,44 @@ static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size return 0; if(size1 > SIZE_MAX / size2) return 0; - return malloc(size1*size2); + return malloc_(size1*size2); } static inline void *safe_realloc_(void *ptr, size_t size) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Fail if requested */ + if(alloc_check() && size > 0) { + free(ptr); + return NULL; + } +#endif void *oldptr = ptr; void *newptr = realloc(ptr, size); if(size > 0 && newptr == 0) free(oldptr); return newptr; } + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +static inline void *realloc_(void *ptr, size_t size) +{ + /* Fail if requested */ + if(alloc_check()) + return NULL; + return realloc(ptr, size); +} +#else +#define realloc_ realloc +#endif + + static inline void *safe_realloc_nofree_add_2op_(void *ptr, size_t size1, size_t size2) { size2 += size1; if(size2 < size1) return 0; - return realloc(ptr, size2); + return realloc_(ptr, size2); } static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) @@ -192,7 +252,7 @@ static inline void *safe_realloc_nofree_add_3op_(void *ptr, size_t size1, size_t size3 += size2; if(size3 < size2) return 0; - return realloc(ptr, size3); + return realloc_(ptr, size3); } static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) @@ -206,7 +266,7 @@ static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size4 += size3; if(size4 < size3) return 0; - return realloc(ptr, size4); + return realloc_(ptr, size4); } static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) @@ -226,7 +286,7 @@ static inline void *safe_realloc_nofree_mul_2op_(void *ptr, size_t size1, size_t return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ if(size1 > SIZE_MAX / size2) return 0; - return realloc(ptr, size1*size2); + return realloc_(ptr, size1*size2); } /* size1 * (size2 + size3) */ diff --git a/oss-fuzz/fuzzer_decoder.cc b/oss-fuzz/fuzzer_decoder.cc index 4afe11b9..b04e2a00 100644 --- a/oss-fuzz/fuzzer_decoder.cc +++ b/oss-fuzz/fuzzer_decoder.cc @@ -29,6 +29,7 @@ #include "FLAC++/decoder.h" #include "FLAC++/metadata.h" +#include "fuzzer_common.h" template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) { (void)id; diff --git a/oss-fuzz/fuzzer_encoder.cc b/oss-fuzz/fuzzer_encoder.cc index f38bdf26..ceaabbb4 100644 --- a/oss-fuzz/fuzzer_encoder.cc +++ b/oss-fuzz/fuzzer_encoder.cc @@ -29,6 +29,7 @@ #include <fuzzing/memory.hpp> #include "FLAC++/encoder.h" +#include "fuzzer_common.h" #define SAMPLE_VALUE_LIMIT (1024*1024*10) diff --git a/oss-fuzz/fuzzer_encoder_v2.cc b/oss-fuzz/fuzzer_encoder_v2.cc index 6b5fc779..b00bc623 100644 --- a/oss-fuzz/fuzzer_encoder_v2.cc +++ b/oss-fuzz/fuzzer_encoder_v2.cc @@ -36,6 +36,7 @@ extern "C" { #include "share/private.h" } +#include "fuzzer_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 @@ -52,6 +53,7 @@ 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; @@ -63,6 +65,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 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"); @@ -154,7 +165,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) encoder_valid &= FLAC__stream_encoder_disable_verbatim_subframes(encoder, data_bools[12]); } - /* data_bools[14..15] are spare */ + /* Disable alloc check if requested */ + if(data_bools[14]) + alloc_check_threshold = INT32_MAX; + + /* data_bools[15] are spare */ /* add metadata */ if(encoder_valid && (metadata_mask & 1)) { @@ -196,13 +211,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Nothing to 🤔 report")) encoder_valid = false; else { - 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 🤔🤣")) - encoder_valid = false; + 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 🤔🤣")) + encoder_valid = false; + else + if(!FLAC__metadata_object_vorbiscomment_insert_comment(metadata[num_metadata++], 0, VorbisCommentField, false)) + free(VorbisCommentField.entry); + } else - FLAC__metadata_object_vorbiscomment_insert_comment(metadata[num_metadata++], 0, VorbisCommentField, false); + free(VorbisCommentField.entry); } } } @@ -262,11 +281,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) } } - if(FLAC__stream_encoder_get_state(encoder) != FLAC__STREAM_ENCODER_OK && - FLAC__stream_encoder_get_state(encoder) != FLAC__STREAM_ENCODER_UNINITIALIZED && - FLAC__stream_encoder_get_state(encoder) != FLAC__STREAM_ENCODER_CLIENT_ERROR){ + 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) && + alloc_check_threshold < INT32_MAX))) { fprintf(stderr,"-----\nERROR: stream encoder returned %s\n-----\n",FLAC__stream_encoder_get_resolved_state_string(encoder)); - if(FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) { + 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); diff --git a/oss-fuzz/fuzzer_metadata.cc b/oss-fuzz/fuzzer_metadata.cc index 3379ecaf..7d3cb5ea 100644 --- a/oss-fuzz/fuzzer_metadata.cc +++ b/oss-fuzz/fuzzer_metadata.cc @@ -34,8 +34,9 @@ #include <cstring> /* for memcpy */ #include <unistd.h> #include "FLAC++/metadata.h" +#include "fuzzer_common.h" -#define CONFIG_LENGTH 1 +#define CONFIG_LENGTH 2 #define min(x,y) (x<y?x:y) @@ -60,6 +61,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) command_length = data[0] >> 4; + if(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; diff --git a/oss-fuzz/fuzzer_seek.cc b/oss-fuzz/fuzzer_seek.cc index ed3df38e..023ac405 100644 --- a/oss-fuzz/fuzzer_seek.cc +++ b/oss-fuzz/fuzzer_seek.cc @@ -32,6 +32,7 @@ #include <cstdlib> #include <cstring> /* for memcpy */ #include "FLAC/stream_decoder.h" +#include "fuzzer_common.h" #if 0 /* set to 1 to debug */ #define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__) @@ -39,7 +40,7 @@ #define FPRINTF_DEBUG_ONLY(...) #endif -#define CONFIG_LENGTH 1 +#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) { @@ -60,6 +61,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 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; + + /* allocate the decoder */ if((decoder = FLAC__stream_decoder_new()) == NULL) { fprintf(stderr, "ERROR: allocating decoder\n"); |