diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh index 43f11d8cc178b896353db3c43bc3daa6f67c9d2d..68528bc46ae7d76f1b6804b97ec2db2dd2f5dd80 100755 --- a/.clusterfuzzlite/build.sh +++ b/.clusterfuzzlite/build.sh @@ -13,10 +13,10 @@ meson setup "$BUILD" \ -Dfuzzer_ldflags="$LIB_FUZZING_ENGINE" \ -Ddebug_level=0 \ -Ddefault_library=static \ - -Db_lundef=false + -Db_lundef=false # build fuzzers -ninja -v -C "$BUILD" test/fuzz/fuzz_{round_trip,compression} +ninja -v -C "$BUILD" test/fuzz/{fuzz_round_trip,fuzz_compression,fuzz_decompression} find "$BUILD/test/fuzz" -maxdepth 1 -executable -type f -exec cp "{}" "$OUT" \; #TODO prepare corps diff --git a/examples/meson.build b/examples/meson.build index 460db1d366a97ddc165fc20b69f6318f087dce26..909339eedb86d64b6926989f205913cc193e05f9 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -2,7 +2,7 @@ example_cmp_rdcu_src = files([ 'example_cmp_rdcu.c' ]) -example_cmp_rdcu_lib = executable('example_cmp_rdcu', +example_cmp_rdcu_lib = static_library('example_cmp_rdcu', sources : example_cmp_rdcu_src, include_directories : incdir, link_with : cmp_lib, diff --git a/meson.build b/meson.build index 1fa2ae79988dc43d5acf20ba9b39d2b679cac725..f2d9ed5c0de01af1ca214b383a0dd58cc6ebb382 100644 --- a/meson.build +++ b/meson.build @@ -53,6 +53,9 @@ if ['windows', 'cygwin'].contains(host_machine.system()) and cc.get_id() == 'gcc add_global_link_arguments('-static', language: 'c') endif +if get_option('fuzzer').enabled() + add_global_arguments('-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION', language: ['c', 'cpp']) +endif # Subdirs subdir('lib') diff --git a/test/fuzz/fuzz_decompression.c b/test/fuzz/fuzz_decompression.c new file mode 100644 index 0000000000000000000000000000000000000000..01ade21a0ae28b95a810b4c630e04307d8fc5171 --- /dev/null +++ b/test/fuzz/fuzz_decompression.c @@ -0,0 +1,103 @@ +/** + * @file defuzz_compression.c + * @date 2024 + * + * @copyright GPLv2 + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * @brief decompression fuzz target + */ + + +#include <stdint.h> +#include <stddef.h> +#include <string.h> + +#include "fuzz_helpers.h" +#include "fuzz_data_producer.h" +#include "../test_common/test_common.h" + +#include "../../lib/decmp.h" + + +int decompress_cmp_entiy_save(const struct cmp_entity *ent, size_t ent_size, const void *model_of_data, + void *up_model_buf, void *decompressed_data, size_t decmp_size) +{ + if (ent && ent_size < GENERIC_HEADER_SIZE) + return -1; + if (cmp_ent_get_size(ent) > ent_size) + return -1; + + if (ent && (decompressed_data || up_model_buf)) { + int decmp_size_ent = decompress_cmp_entiy(ent, model_of_data, NULL, NULL); + if (decmp_size < (size_t)decmp_size_ent || decmp_size_ent < 0) + return -1; + } + + return decompress_cmp_entiy(ent, model_of_data, up_model_buf, decompressed_data); +} + +int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) +{ + const struct cmp_entity *ent = NULL; + const void *model_of_data = NULL; + void *up_model_buf; + uint32_t model_of_data_size; + uint32_t ent_size; + void *decompressed_data; + + /* Give a random portion of src data to the producer, to use for + parameter generation. The rest will be used for data/model */ + FUZZ_dataProducer_t *producer = (FUZZ_dataProducer_t *)FUZZ_dataProducer_create(src, size); + size = FUZZ_dataProducer_reserveDataPrefix(producer); + FUZZ_ASSERT(size <= UINT32_MAX); + + /* spilt data to compressed data and model data */ + ent_size = FUZZ_dataProducer_uint32Range(producer, 0, (uint32_t)size); + model_of_data_size = FUZZ_dataProducer_uint32Range(producer, 0, (uint32_t)size-ent_size); + + if (ent_size) + ent = (const struct cmp_entity *)src; + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) { + model_of_data = src + ent_size; + } else { + model_of_data = NULL; + } + + + switch (FUZZ_dataProducer_int32Range(producer, 0, 2)) { + case 0: + up_model_buf = NULL; + break; + case 1: + up_model_buf = TEST_malloc(model_of_data_size); + break; + case 2: /* in-place update */ + up_model_buf = TEST_malloc(model_of_data_size); + if (model_of_data && up_model_buf) { + memcpy(up_model_buf, model_of_data, model_of_data_size); + model_of_data = up_model_buf; + } + break; + default: + FUZZ_ASSERT(0); + } + + decompressed_data = TEST_malloc((size_t)model_of_data_size); + decompress_cmp_entiy_save(ent, ent_size, model_of_data, up_model_buf, decompressed_data, model_of_data_size); + + free(up_model_buf); + free(decompressed_data); + FUZZ_dataProducer_free(producer); + + return 0; +} + + diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build index 3815fcf6885beb99ba9f37e060083f7e8f90e18b..89d67ad7ab120271d3baecaf616e475ee0ddfa7e 100644 --- a/test/fuzz/meson.build +++ b/test/fuzz/meson.build @@ -3,7 +3,7 @@ if get_option('fuzzer').disabled() endif fuzz_common = files('fuzz_data_producer.c') -fuzz_targets = ['fuzz_compression.c', 'fuzz_round_trip.c'] +fuzz_targets = ['fuzz_compression.c', 'fuzz_round_trip.c', 'fuzz_decompression.c'] add_languages('cpp', native: false) # libFuzzingEngine needs c++