From b347eaa8735336b030826c742baac763e03b3a80 Mon Sep 17 00:00:00 2001 From: Arthur Chan Date: Fri, 12 Jun 2026 19:12:18 +0100 Subject: [PATCH] OSS-Fuzz: Move fuzzers upstream Signed-off-by: Arthur Chan --- CMakeLists.txt | 10 +++++++ test/fuzzing/CMakeLists.txt | 42 +++++++++++++++++++++++++++++ test/fuzzing/h5_extended_fuzzer.c | 42 +++++++++++++++++++++++++++++ test/fuzzing/h5_read_fuzzer.c | 44 +++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 test/fuzzing/CMakeLists.txt create mode 100644 test/fuzzing/h5_extended_fuzzer.c create mode 100644 test/fuzzing/h5_read_fuzzer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cb58250215..ace6ea5bf32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1545,3 +1545,13 @@ include (CMakeInstallation.cmake) #----------------------------------------------------------------------------- mark_as_advanced (FETCHCONTENT_BASE_DIR FETCHCONTENT_FULLY_DISCONNECTED FETCHCONTENT_QUIET FETCHCONTENT_UPDATES_DISCONNECTED) +#----------------------------------------------------------------------------- +# libFuzzer harnesses (OSS-Fuzz). Off by default; when enabled, build them with +# the `oss-fuzz-fuzzers` target. Placed after all add_subdirectory() calls so the +# HDF5 library targets are defined. +#----------------------------------------------------------------------------- +option (HDF5_ENABLE_FUZZERS "Build the libFuzzer harnesses in test/fuzzing" OFF) +if (HDF5_ENABLE_FUZZERS) + add_subdirectory (test/fuzzing) +endif () + diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt new file mode 100644 index 00000000000..44586e1d563 --- /dev/null +++ b/test/fuzzing/CMakeLists.txt @@ -0,0 +1,42 @@ +#----------------------------------------------------------------------------- +# libFuzzer harnesses for OSS-Fuzz. Enabled with -DHDF5_ENABLE_FUZZERS=ON. +# +# Each harness links the static HDF5 library plus a fuzzing engine: OSS-Fuzz +# provides one via the LIB_FUZZING_ENGINE environment variable; a standalone +# developer build falls back to -fsanitize=fuzzer. Build them all at once with +# the `oss-fuzz-fuzzers` target. +#----------------------------------------------------------------------------- + +# The harnesses are C, but the fuzzing engine is C++ and we link with the C++ +# driver; ensure CXX is enabled in this scope so CMAKE_CXX_LINK_EXECUTABLE is set +# (HDF5 only enables CXX inside its c++/ subdirectory). +enable_language (CXX) + +set (HDF5_FUZZERS + h5_read_fuzzer + h5_extended_fuzzer +) + +foreach (fuzzer ${HDF5_FUZZERS}) + add_executable (${fuzzer} "${CMAKE_CURRENT_SOURCE_DIR}/${fuzzer}.c") + + target_include_directories (${fuzzer} PRIVATE + "${CMAKE_SOURCE_DIR}/src" + "${CMAKE_BINARY_DIR}/src" + "${CMAKE_SOURCE_DIR}/src/H5FDsubfiling" + ) + + target_link_libraries (${fuzzer} PRIVATE ${HDF5_LIB_TARGET} z) + + # libFuzzer supplies its own main(); link with the C++ driver. + set_target_properties (${fuzzer} PROPERTIES LINKER_LANGUAGE CXX) + + if (DEFINED ENV{LIB_FUZZING_ENGINE}) + target_link_libraries (${fuzzer} PRIVATE "$ENV{LIB_FUZZING_ENGINE}") + else () + target_compile_options (${fuzzer} PRIVATE -fsanitize=fuzzer) + target_link_options (${fuzzer} PRIVATE -fsanitize=fuzzer) + endif () +endforeach () + +add_custom_target (oss-fuzz-fuzzers DEPENDS ${HDF5_FUZZERS}) diff --git a/test/fuzzing/h5_extended_fuzzer.c b/test/fuzzing/h5_extended_fuzzer.c new file mode 100644 index 00000000000..18f01e00853 --- /dev/null +++ b/test/fuzzing/h5_extended_fuzzer.c @@ -0,0 +1,42 @@ +/* Copyright 2023 Google LLC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "hdf5.h" + +#include + +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d", getpid()); + + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return 0; + } + fwrite(data, size, 1, fp); + fclose(fp); + + hid_t fuzz_h5_id = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + if (fuzz_h5_id != H5I_INVALID_HID) { + hid_t dataset_id = H5Dopen2(fuzz_h5_id, "dsetname", H5P_DEFAULT); + if (dataset_id != H5I_INVALID_HID) { + hid_t attribute_id = H5Aopen_name(dataset_id, "theattr"); + if (attribute_id != H5I_INVALID_HID) { + H5Aclose(attribute_id); + } + H5Dclose(dataset_id); + } + H5Fclose(fuzz_h5_id); + } + return 0; +} diff --git a/test/fuzzing/h5_read_fuzzer.c b/test/fuzzing/h5_read_fuzzer.c new file mode 100644 index 00000000000..6dbb6459b2d --- /dev/null +++ b/test/fuzzing/h5_read_fuzzer.c @@ -0,0 +1,44 @@ +/* Copyright 2023 Google LLC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "hdf5.h" + +#include + +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + // Some old logic with regards to skipping first byte. Leaving it here + // to avoid affecting the clusterfuzz-generated corpus. + if (size == 0) { + return 0; + } + uint8_t decider = data[0]; + size -= 1; + data += 1; + + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d", getpid()); + + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return 0; + } + fwrite(data, size, 1, fp); + fclose(fp); + + hid_t fuzz_h5_id = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + if (fuzz_h5_id != H5I_INVALID_HID) { + H5Fclose(fuzz_h5_id); + } + + return 0; +}