Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()

42 changes: 42 additions & 0 deletions test/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
42 changes: 42 additions & 0 deletions test/fuzzing/h5_extended_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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 <unistd.h>

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;
}
44 changes: 44 additions & 0 deletions test/fuzzing/h5_read_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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 <unistd.h>

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;
}