summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartijn van Beurden <mvanb1@gmail.com>2022-08-11 14:09:39 +0200
committerMartijn van Beurden <mvanb1@gmail.com>2022-08-20 16:03:53 +0200
commitfbb6cb5c075d24ce35ccad6ca18f9cbbdb4e3d3f (patch)
tree567b3bf9467bf15dd99410b4c18c06fd69cec5c2
parent707dace4bd82cd6042e524c72544ab50de223a10 (diff)
downloadflac-fbb6cb5c075d24ce35ccad6ca18f9cbbdb4e3d3f.tar.gz
Add OOM checking to fuzzing
-rw-r--r--include/share/alloc.h72
-rw-r--r--oss-fuzz/fuzzer_decoder.cc1
-rw-r--r--oss-fuzz/fuzzer_encoder.cc1
-rw-r--r--oss-fuzz/fuzzer_encoder_v2.cc45
-rw-r--r--oss-fuzz/fuzzer_metadata.cc10
-rw-r--r--oss-fuzz/fuzzer_seek.cc10
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");