diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ab058..156df83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,6 +278,7 @@ if(BUILD_FUZZERS) set(SMALL_FUZZER_SRC_LIST "${FUZZ_MAIN_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/small_fuzzer.c") set(LARGE_FUZZER_SRC_LIST "${FUZZ_MAIN_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/large_fuzzer.c") set(ZIP_FUZZER_SRC_LIST "${FUZZ_MAIN_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/zip_fuzzer.c") + set(ADD_IN_PLACE_FUZZER_SRC_LIST "${FUZZ_MAIN_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/add_in_place_fuzzer.c") add_executable(checksum_fuzzer ${CHECKSUM_FUZZER_SRC_LIST}) target_link_libraries(checksum_fuzzer miniz) @@ -302,6 +303,9 @@ if(BUILD_FUZZERS) add_executable(zip_fuzzer ${ZIP_FUZZER_SRC_LIST}) target_link_libraries(zip_fuzzer miniz) + + add_executable(add_in_place_fuzzer ${ADD_IN_PLACE_FUZZER_SRC_LIST}) + target_link_libraries(add_in_place_fuzzer miniz) endif() if(BUILD_TESTS) diff --git a/tests/add_in_place_fuzzer.c b/tests/add_in_place_fuzzer.c new file mode 100644 index 0000000..3f4e990 --- /dev/null +++ b/tests/add_in_place_fuzzer.c @@ -0,0 +1,87 @@ +#include +#include +#include "miniz.h" + +static const mz_uint files_count = 5; +static const mz_uint max_file_size = 1024 * 1024; +static const char *zip_file_name = "/tmp/miniz-fuzzer-test.zip"; + +/* Read 32-bit integer from the fuzzer input with range [0, max] */ +static mz_uint read_uint32(const mz_uint8 **data, size_t *size, mz_uint max) +{ + mz_uint value = 0; + + if (*size >= sizeof(mz_uint)) + { + memcpy(&value, *data, sizeof(mz_uint)); + *data += sizeof(mz_uint); + *size -= sizeof(mz_uint); + value = MZ_MIN(max == UINT_MAX ? value : value % (max + 1), *size); + } + + return value; +} + +/* Read random-length null terminated string from the fuzzer input */ +static mz_bool read_string(const mz_uint8 **data, size_t *size, char *destination, mz_uint max_len) +{ + mz_uint filename_len = read_uint32(data, size, max_len - 1); + memcpy(destination, *data, filename_len); + destination[filename_len] = 0; + *data += filename_len; + *size -= filename_len; + return filename_len > 0; +} + +/* Get random-length buffer from the fuzzer input */ +static mz_bool read_buffer(const mz_uint8 **data, size_t *size, const mz_uint8 **destination, mz_uint *len) +{ + *len = read_uint32(data, size, max_file_size); + *destination = *data; + *data += *len; + *size -= *len; + return *len > 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + mz_uint i; + char archive_file_name[FILENAME_MAX]; + const mz_uint8 *file_data; + mz_uint file_length, flags; + size_t extracted_size; + mz_uint8 *extracted_data; + const char *comment = mz_version(); + + /* Remove the temporary file for better reproducibility */ + remove(zip_file_name); + + for (i = 0; i < files_count; ++i) + { + /* Fill archive file name */ + if (!read_string(&data, &size, archive_file_name, sizeof(archive_file_name))) + { + break; + } + + /* Prepare file's content */ + if (!read_buffer(&data, &size, &file_data, &file_length)) + { + break; + } + + /* Prepare flags for adding file */ + flags = read_uint32(&data, &size, UINT_MAX); + + mz_zip_add_mem_to_archive_file_in_place(zip_file_name, archive_file_name, file_data, file_length, comment, + (mz_uint16)strlen(comment), flags); + + /* Prepare flags for extracting file */ + flags = read_uint32(&data, &size, UINT_MAX); + extracted_data = mz_zip_extract_archive_file_to_heap(zip_file_name, archive_file_name, &extracted_size, flags); + free(extracted_data); + } + + remove(zip_file_name); + return 0; +}