diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 771dc5cd5e..1b8ac70e17 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -17,4 +17,5 @@ include("${CMAKE_SOURCE_DIR}/cmake/Modules/Generate.cmake") add_subdirectory(fuzz_config_init) add_subdirectory(fuzz_handle_rtps_message) add_subdirectory(fuzz_type_object) +add_subdirectory(fuzz_sample_deser) # add_subdirectory(fuzz_idlc) diff --git a/fuzz/fuzz_sample_deser/CMakeLists.txt b/fuzz/fuzz_sample_deser/CMakeLists.txt new file mode 100644 index 0000000000..d2e0c21ea7 --- /dev/null +++ b/fuzz/fuzz_sample_deser/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.5) +project(fuzz_sample_deser LANGUAGES C) + +if(NOT TARGET CycloneDDS::ddsc) + # Find the CycloneDDS package. + find_package(CycloneDDS REQUIRED) +endif() + +idlc_generate(TARGET fuzz_sample FILES fuzz_sample.idl WARNINGS no-implicit-extensibility) +add_executable(fuzz_sample_deser fuzz_sample_deser.c fuzz_sample.c) +target_include_directories( + fuzz_sample_deser PRIVATE + "$/" + "$" + "$" + "$" + "$") + +target_compile_options(fuzz_sample_deser PRIVATE -fsanitize=fuzzer,address -g) +target_link_libraries(fuzz_sample_deser fuzz_sample CycloneDDS::ddsc -fsanitize=fuzzer,address) diff --git a/fuzz/fuzz_sample_deser/fuzz_sample_deser.c b/fuzz/fuzz_sample_deser/fuzz_sample_deser.c new file mode 100644 index 0000000000..3b7502371a --- /dev/null +++ b/fuzz/fuzz_sample_deser/fuzz_sample_deser.c @@ -0,0 +1,35 @@ +#include +#include +#include + +#include "fuzz_samples.h" + +static void __attribute__((constructor)) print_idl_types_seed() { + printf("IDL types seed: %s\n", idl_types_seed); +} + +static void topic_to_descriptor(struct dds_cdrstream_desc *desc, const dds_topic_descriptor_t *t) { + memset(desc, 0, sizeof(struct dds_cdrstream_desc)); + dds_cdrstream_desc_init(desc, &dds_cdrstream_default_allocator, t->m_size, t->m_align, t->m_flagset, t->m_ops, NULL, 0); +} + +int LLVMFuzzerTestOneInput(void *data, size_t size) +{ + uint32_t actual_size; + + for(size_t i = 0; i < sizeof(fixed_types)/sizeof(fixed_types[0]); i++) { + const struct dds_topic_descriptor *topic = fixed_types[i]; + struct dds_cdrstream_desc desc; + topic_to_descriptor(&desc, topic); + if (dds_stream_normalize(data, (uint32_t) size, false, DDSI_RTPS_CDR_ENC_VERSION_2, &desc, false, &actual_size)) { + void *sample = ddsrt_calloc(1, desc.size); + dds_istream_t is; + dds_istream_init(&is, (uint32_t) size, data, DDSI_RTPS_CDR_ENC_VERSION_2); + dds_stream_read_sample(&is, sample, &dds_cdrstream_default_allocator, &desc); + dds_stream_free_sample(sample, &dds_cdrstream_default_allocator, desc.ops.ops); + ddsrt_free(sample); + } + dds_cdrstream_desc_fini(&desc, &dds_cdrstream_default_allocator); + } + return 0; +} diff --git a/fuzz/fuzz_sample_deser/generate_idl.py b/fuzz/fuzz_sample_deser/generate_idl.py new file mode 100644 index 0000000000..e657e1f71f --- /dev/null +++ b/fuzz/fuzz_sample_deser/generate_idl.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +import sys +import os +from fuzz_tools.rand_idl.creator import generate_random_types, generate_random_idl +from fuzz_tools.rand_idl.value import generate_random_instance +from fuzz_tools.rand_idl.compile import compile_idl + +def die(code, s): + print(s, file=sys.stderr) + sys.exit(code) + +MODULE_NAME = "Fuzz" +CORPUS="fuzz_sample_deser_seed_corpus" +if __name__ == '__main__': + if len(sys.argv) != 3: + die(0, "Usage: {} ") + seed = int(sys.argv[1], 16) + directory = sys.argv[2] + if not os.path.isdir(directory): + die(-1, f"{directory} is not a directory") + + # Generate random idl + scope = generate_random_types(MODULE_NAME, number=25, seed=seed) + idl_text = generate_random_idl(scope) + with open(os.path.join(directory, "fuzz_sample.idl"), "w") as f: + f.write(idl_text) + + # Hacky way to identify top-level types. + toplvltypes = [e for e in scope.entities if getattr(e, "extensibility", False)] + # Generate fuzz_samples.h, collecting all generated types + with open(os.path.join(directory, "fuzz_samples.h"), "w") as f: + f.write("#include \"fuzz_sample.h\"\n") + f.write("static const char *idl_types_seed = \"{}\";".format(sys.argv[1])) + f.write("static const struct dds_topic_descriptor *fixed_types[] = {\n") + for entity in toplvltypes: + entry = "&{}_{}_desc".format(MODULE_NAME, entity.name) + if entity != scope.entities[-1]: + f.write(f"\t{entry},\n") + else: + f.write(f"\t{entry}\n") + f.write("};\n") + + # Generate initial corpus + imported, tdir = compile_idl(idl_text, MODULE_NAME) + corpus = os.path.join(directory, CORPUS) + if not os.path.isdir(corpus): + os.mkdir(corpus) + for entity in toplvltypes: + t = getattr(imported.__fuzzytypes, entity.name) + sample = generate_random_instance(t, seed=seed) + fname = "seed_{}".format(entity.name) + with open(os.path.join(corpus, fname), "wb") as f: + f.write(sample.serialize()) diff --git a/fuzz/fuzz_sample_deser/prepare.sh b/fuzz/fuzz_sample_deser/prepare.sh new file mode 100644 index 0000000000..1813862a5c --- /dev/null +++ b/fuzz/fuzz_sample_deser/prepare.sh @@ -0,0 +1,34 @@ +#!/bin/bash -eu + +prepare_fuzz_deser() { + apt-get -y install python3 python3-pip libssl-dev + mkdir -p build_python install + export CYCLONEDDS_HOME="$(pwd)/install" + fuzzer="$(pwd)/fuzz/fuzz_sample_deser" + cd build_python + + # This builds cyclone for the python tool, the fuzzer is built later + cmake \ + -DBUILD_IDLC=ON \ + -DBUILD_TESTING=OFF \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_EXAMPLES=NO \ + -DENABLE_SECURITY=NO \ + -DENABLE_SSL=NO \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ + -DCMAKE_INSTALL_PREFIX=../install .. + cmake --build . + cmake --build . --target install + + rm -rf cyclonedds-python + git clone --depth=1 https://github.com/eclipse-cyclonedds/cyclonedds-python.git + pip3 install ./cyclonedds-python + ln -sf "$(pwd)/cyclonedds-python/tests/support_modules/fuzz_tools" "${fuzzer}/fuzz_tools" + + # Use current git HEAD hash as seed + seed=$(git ls-remote https://github.com/eclipse-cyclonedds/cyclonedds HEAD |cut -f1) + PATH=${CYCLONEDDS_HOME}/bin:$PATH python3 "${fuzzer}/generate_idl.py" $seed "${fuzzer}" +} + +export -f prepare_fuzz_deser +env -u CFLAGS -u CXXFLAGS -u LIB_FUZZING_ENGINE bash -euc prepare_fuzz_deser diff --git a/fuzz/oss-fuzz-build.sh b/fuzz/oss-fuzz-build.sh index 02dde69421..29176988ea 100644 --- a/fuzz/oss-fuzz-build.sh +++ b/fuzz/oss-fuzz-build.sh @@ -12,6 +12,7 @@ # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # +source fuzz/fuzz_sample_deser/prepare.sh ( mkdir build cd build