Skip to content

Commit 5c36110

Browse files
authored
[Fuzzer] Add two new ORT libfuzzer (Linux clang support for now) (microsoft#22055)
### Description This PR adds two new libfuzzer in fuzzer project. 1. Binary libfuzzer 2. libprotobuf-fuzzer To compile run below cmd on linux: ``` LLVM_PROFILE_FILE="%p.profraw" CFLAGS="-g -fsanitize=address,fuzzer-no-link -shared-libasan -fprofile-instr-generate -fcoverage-mapping" CXXFLAGS="-g -shared-libasan -fsanitize=address,fuzzer-no-link -fprofile-instr-generate -fcoverage-mapping" CC=clang CXX=clang++ ./build.sh --update --build --config Debug --compile_no_warning_as_error --build_shared_lib --skip_submodule_sync --use_full_protobuf --parallel --fuzz_testing --build_dir build/ ``` Run fuzzer: ``` LD_PRELOAD=$(clang -print-file-name=libclang_rt.asan-x86_64.so) build/Debug/onnxruntime_libfuzzer_fuzz testinput -rss_limit_mb=8196 -max_total_time=472800 -fork=2 -jobs=4 -workers=4 -ignore_crashes=1 -max_len=2097152 2>&1 | grep -v "\[libprotobuf ERROR" ``` ### Motivation and Context The existing custom fuzzer is not coverage guided and it's slow and it will work on one model mutation at a time. The new fuzzers are coverage guided, and we can use more models' files as a corpus to increase the coverage.
1 parent d539c27 commit 5c36110

File tree

3 files changed

+236
-45
lines changed

3 files changed

+236
-45
lines changed

cmake/onnxruntime_fuzz_test.cmake

Lines changed: 100 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,24 @@
44
# Check that the options are properly set for
55
# the fuzzing project
66
if (onnxruntime_FUZZ_ENABLED)
7-
message(STATUS "Building dependency protobuf-mutator and libfuzzer")
8-
9-
# set the options used to control the protobuf-mutator build
10-
set(PROTOBUF_LIBRARIES ${PROTOBUF_LIB})
11-
set(LIB_PROTO_MUTATOR_TESTING OFF)
12-
13-
# include the protobuf-mutator CMakeLists.txt rather than the projects CMakeLists.txt to avoid target clashes
14-
# with google test
15-
add_subdirectory("external/libprotobuf-mutator/src")
16-
17-
# add the appropriate include directory and compilation flags
18-
# needed by the protobuf-mutator target and the libfuzzer
19-
set(PROTOBUF_MUT_INCLUDE_DIRS "external/libprotobuf-mutator")
20-
onnxruntime_add_include_to_target(protobuf-mutator ${PROTOBUF_LIB})
21-
onnxruntime_add_include_to_target(protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
22-
target_include_directories(protobuf-mutator PRIVATE ${INCLUDE_DIRECTORIES} ${PROTOBUF_MUT_INCLUDE_DIRS})
23-
target_include_directories(protobuf-mutator-libfuzzer PRIVATE ${INCLUDE_DIRECTORIES} ${PROTOBUF_MUT_INCLUDE_DIRS})
7+
message(STATUS "Building dependency protobuf-mutator and libfuzzer")
8+
9+
# set the options used to control the protobuf-mutator build
10+
set(PROTOBUF_LIBRARIES ${PROTOBUF_LIB})
11+
set(LIB_PROTO_MUTATOR_TESTING OFF)
12+
13+
# include the protobuf-mutator CMakeLists.txt rather than the projects CMakeLists.txt to avoid target clashes
14+
# with google test
15+
add_subdirectory("external/libprotobuf-mutator/src")
16+
17+
# add the appropriate include directory and compilation flags
18+
# needed by the protobuf-mutator target and the libfuzzer
19+
set(PROTOBUF_MUT_INCLUDE_DIRS "external/libprotobuf-mutator")
20+
onnxruntime_add_include_to_target(protobuf-mutator ${PROTOBUF_LIB})
21+
onnxruntime_add_include_to_target(protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
22+
target_include_directories(protobuf-mutator PRIVATE ${INCLUDE_DIRECTORIES} ${PROTOBUF_MUT_INCLUDE_DIRS})
23+
target_include_directories(protobuf-mutator-libfuzzer PRIVATE ${INCLUDE_DIRECTORIES} ${PROTOBUF_MUT_INCLUDE_DIRS})
24+
2425
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
2526
# MSVC-specific compiler options
2627
target_compile_options(protobuf-mutator PRIVATE "/wd4244" "/wd4245" "/wd4267" "/wd4100" "/wd4456")
@@ -44,42 +45,96 @@ if (onnxruntime_FUZZ_ENABLED)
4445
)
4546
endif()
4647

47-
# add Fuzzing Engine Build Configuration
48-
message(STATUS "Building Fuzzing engine")
48+
# add Fuzzing Engine Build Configuration
49+
message(STATUS "Building Fuzzing engine")
50+
51+
# set Fuzz root directory
52+
set(SEC_FUZZ_ROOT ${TEST_SRC_DIR}/fuzzing)
53+
54+
# Security fuzzing engine src file reference
55+
set(SEC_FUZ_SRC "${SEC_FUZZ_ROOT}/src/BetaDistribution.cpp"
56+
"${SEC_FUZZ_ROOT}/src/OnnxPrediction.cpp"
57+
"${SEC_FUZZ_ROOT}/src/testlog.cpp"
58+
"${SEC_FUZZ_ROOT}/src/test.cpp")
59+
60+
# compile the executables
61+
onnxruntime_add_executable(onnxruntime_security_fuzz ${SEC_FUZ_SRC})
62+
63+
# compile with c++17
64+
target_compile_features(onnxruntime_security_fuzz PUBLIC cxx_std_17)
4965

50-
# set Fuzz root directory
51-
set(SEC_FUZZ_ROOT ${TEST_SRC_DIR}/fuzzing)
66+
# Security fuzzing engine header file reference
67+
onnxruntime_add_include_to_target(onnxruntime_security_fuzz onnx onnxruntime)
5268

53-
# Security fuzzing engine src file reference
54-
set(SEC_FUZ_SRC "${SEC_FUZZ_ROOT}/src/BetaDistribution.cpp"
55-
"${SEC_FUZZ_ROOT}/src/OnnxPrediction.cpp"
56-
"${SEC_FUZZ_ROOT}/src/testlog.cpp"
57-
"${SEC_FUZZ_ROOT}/src/test.cpp")
69+
# Assign all include to one variable
70+
set(SEC_FUZ_INC "${SEC_FUZZ_ROOT}/include")
71+
set(INCLUDE_FILES ${SEC_FUZ_INC} "$<TARGET_PROPERTY:protobuf-mutator,INCLUDE_DIRECTORIES>")
5872

59-
# compile the executables
60-
onnxruntime_add_executable(onnxruntime_security_fuzz ${SEC_FUZ_SRC})
73+
# add all these include directory to the Fuzzing engine
74+
target_include_directories(onnxruntime_security_fuzz PRIVATE ${INCLUDE_FILES})
6175

62-
# compile with c++17
63-
target_compile_features(onnxruntime_security_fuzz PUBLIC cxx_std_17)
76+
# add link libraries to the project
77+
target_link_libraries(onnxruntime_security_fuzz onnx_proto onnxruntime protobuf-mutator ${PROTOBUF_LIB})
6478

65-
# Security fuzzing engine header file reference
66-
onnxruntime_add_include_to_target(onnxruntime_security_fuzz onnx onnxruntime)
79+
# add the dependencies
80+
add_dependencies(onnxruntime_security_fuzz onnx_proto onnxruntime protobuf-mutator ${PROTOBUF_LIB})
6781

68-
# Assign all include to one variable
69-
set(SEC_FUZ_INC "${SEC_FUZZ_ROOT}/include")
70-
set(INCLUDE_FILES ${SEC_FUZ_INC} "$<TARGET_PROPERTY:protobuf-mutator,INCLUDE_DIRECTORIES>")
82+
# copy the shared libraries (DLLs on Windows, SOs on Linux) to the execution directory
83+
add_custom_command(TARGET onnxruntime_security_fuzz POST_BUILD
84+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_security_fuzz>
85+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_security_fuzz>)
7186

72-
# add all these include directory to the Fuzzing engine
73-
target_include_directories(onnxruntime_security_fuzz PRIVATE ${INCLUDE_FILES})
87+
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
88+
# Add a second fuzzer that uses libFuzzer in fuzzer/libfuzzer
89+
message(STATUS "Building libProtoBufFuzzer-based fuzzer")
7490

75-
# add link libraries the project
76-
target_link_libraries(onnxruntime_security_fuzz onnx_proto onnxruntime protobuf-mutator ${PROTOBUF_LIB})
91+
# Set source files for the libFuzzer
92+
set(LIBFUZZER_SRC "${SEC_FUZZ_ROOT}/src/OnnxPrediction.cpp"
93+
"${SEC_FUZZ_ROOT}/src/testlog.cpp"
94+
"${SEC_FUZZ_ROOT}/ort_libfuzzer/OrtProtoLibfuzzer.cpp")
7795

78-
# add the dependencies
79-
add_dependencies(onnxruntime_security_fuzz onnx_proto onnxruntime protobuf-mutator ${PROTOBUF_LIB})
96+
# Compile the libFuzzer-based fuzzer
97+
onnxruntime_add_executable(onnxruntime_proto_libfuzzer ${LIBFUZZER_SRC})
98+
# Security fuzzing engine header file reference
99+
onnxruntime_add_include_to_target(onnxruntime_proto_libfuzzer onnx onnxruntime)
100+
# Set include directories for libFuzzer
101+
target_include_directories(onnxruntime_proto_libfuzzer PRIVATE ${INCLUDE_FILES})
80102

81-
# copy the dlls to the execution directory
82-
add_custom_command(TARGET onnxruntime_security_fuzz POST_BUILD
83-
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_security_fuzz>
84-
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_security_fuzz>)
103+
# Add link libraries for libFuzzer
104+
target_link_libraries(onnxruntime_proto_libfuzzer onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer -fsanitize=fuzzer,address ${PROTOBUF_LIB})
105+
106+
# Add the dependencies for libFuzzer
107+
add_dependencies(onnxruntime_proto_libfuzzer onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
108+
109+
# Copy shared libraries for libFuzzer
110+
add_custom_command(TARGET onnxruntime_proto_libfuzzer POST_BUILD
111+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_proto_libfuzzer>
112+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_proto_libfuzzer>)
113+
# Add a second fuzzer that uses libFuzzer in fuzzer/libfuzzer
114+
message(STATUS "Building libBufFuzzer-based fuzzer")
115+
116+
# Set source files for the libFuzzer
117+
set(LIBFUZZER_SRC "${SEC_FUZZ_ROOT}/src/OnnxPrediction.cpp"
118+
"${SEC_FUZZ_ROOT}/src/testlog.cpp"
119+
"${SEC_FUZZ_ROOT}/ort_libfuzzer/OrtLibfuzzer.cpp")
120+
121+
# Compile the libFuzzer-based fuzzer
122+
onnxruntime_add_executable(onnxruntime_libfuzzer_fuzz ${LIBFUZZER_SRC})
123+
# Security fuzzing engine header file reference
124+
onnxruntime_add_include_to_target(onnxruntime_libfuzzer_fuzz onnx onnxruntime)
125+
# Set include directories for libFuzzer
126+
target_compile_definitions(onnxruntime_libfuzzer_fuzz PRIVATE GOOGLE_PROTOBUF_NO_LOGGING=1)
127+
target_include_directories(onnxruntime_libfuzzer_fuzz PRIVATE ${INCLUDE_FILES})
128+
129+
# Add link libraries for libFuzzer
130+
target_link_libraries(onnxruntime_libfuzzer_fuzz onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer -fsanitize=fuzzer,address ${PROTOBUF_LIB})
131+
132+
# Add the dependencies for libFuzzer
133+
add_dependencies(onnxruntime_libfuzzer_fuzz onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
134+
135+
# Copy shared libraries for libFuzzer
136+
add_custom_command(TARGET onnxruntime_libfuzzer_fuzz POST_BUILD
137+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_libfuzzer_fuzz>
138+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_libfuzzer_fuzz>)
139+
endif()
85140
endif()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#include "OnnxPrediction.h"
5+
#include "onnxruntime_session_options_config_keys.h"
6+
#include "src/libfuzzer/libfuzzer_macro.h"
7+
#include "fuzzer/FuzzedDataProvider.h"
8+
9+
Ort::Env env;
10+
11+
void predict(onnx::ModelProto& msg, unsigned int seed, Ort::Env& env) {
12+
// Create object for prediction
13+
//
14+
OnnxPrediction predict(msg, env);
15+
16+
// Give predict a function to generate the data
17+
// to run prediction on.
18+
//
19+
predict.SetupInput(GenerateDataForInputTypeTensor, seed);
20+
21+
// Run the prediction on the data
22+
//
23+
predict.RunInference();
24+
}
25+
26+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
27+
FuzzedDataProvider data_provider(data, size);
28+
onnx::ModelProto msg;
29+
try {
30+
if (!msg.ParseFromArray(data, static_cast<int>(size))) {
31+
return 0; // Ignore invalid inputs
32+
}
33+
predict(msg, data_provider.ConsumeIntegral<int>(), env);
34+
} catch (const std::exception& e) {
35+
// Optionally log or suppress the exception
36+
// std::cerr << "Caught exception: " << e.what() << std::endl;
37+
} catch (...) {
38+
// Handle any other exceptions
39+
// std::cerr << "Caught unknown exception." << std::endl;
40+
}
41+
return 0;
42+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#include "src/mutator.h"
5+
#include "OnnxPrediction.h"
6+
#include "onnxruntime_session_options_config_keys.h"
7+
#include "src/libfuzzer/libfuzzer_macro.h"
8+
#include "onnx/onnx_pb.h"
9+
10+
#include <type_traits>
11+
12+
Ort::Env env;
13+
14+
std::string wstring_to_string(const std::wstring& wstr) {
15+
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
16+
return converter.to_bytes(wstr);
17+
}
18+
19+
void predict(onnx::ModelProto& msg, unsigned int seed, Ort::Env& env) {
20+
// Create object for prediction
21+
//
22+
OnnxPrediction predict(msg, env);
23+
24+
// Give predict a function to generate the data
25+
// to run prediction on.
26+
//
27+
predict.SetupInput(GenerateDataForInputTypeTensor, seed);
28+
29+
// Run the prediction on the data
30+
//
31+
predict.RunInference();
32+
33+
// View the output
34+
//
35+
predict.PrintOutputValues();
36+
}
37+
38+
template <class Proto>
39+
using PostProcessor =
40+
protobuf_mutator::libfuzzer::PostProcessorRegistration<Proto>;
41+
42+
// Helper function to generate random strings
43+
std::string generate_random_string(size_t length, std::mt19937& rng) {
44+
const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
45+
std::uniform_int_distribution<> dist(0, characters.size() - 1);
46+
std::string result;
47+
for (size_t i = 0; i < length; ++i) {
48+
result += characters[dist(rng)];
49+
}
50+
return result;
51+
}
52+
53+
// Helper function to generate random float
54+
float generate_random_float(std::mt19937& rng) {
55+
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
56+
return dist(rng);
57+
}
58+
59+
// PostProcessor for ONNX ModelProto with random values
60+
static PostProcessor<onnx::ModelProto> reg1 = {
61+
[](onnx::ModelProto* model_proto, unsigned int seed) {
62+
std::mt19937 rng(seed);
63+
64+
// Set model's IR version
65+
model_proto->set_ir_version(7);
66+
67+
model_proto->set_producer_name("onnx");
68+
model_proto->set_producer_version("7.0");
69+
model_proto->set_domain("example.com");
70+
71+
// Add a dummy opset import
72+
auto* opset_import = model_proto->add_opset_import();
73+
opset_import->set_version(10);
74+
75+
// Access the graph from the model
76+
auto* graph = model_proto->mutable_graph();
77+
78+
// Set a random name for the graph
79+
graph->set_name(generate_random_string(10, rng));
80+
}};
81+
82+
DEFINE_PROTO_FUZZER(const onnx::ModelProto& msg) {
83+
try {
84+
auto seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
85+
onnx::ModelProto msg_proto = msg;
86+
predict(msg_proto, seed, env);
87+
} catch (const std::exception& e) {
88+
// Optionally log or suppress the exception
89+
// std::cerr << "Caught exception: " << e.what() << std::endl;
90+
} catch (...) {
91+
// Handle any other exceptions
92+
// std::cerr << "Caught unknown exception." << std::endl;
93+
}
94+
}

0 commit comments

Comments
 (0)