[Fuzzer] Add two new ORT libfuzzer (Linux clang support for now) (#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.
This commit is contained in:
Родитель
d539c27de8
Коммит
5c361106e6
|
@ -21,6 +21,7 @@ if (onnxruntime_FUZZ_ENABLED)
|
|||
onnxruntime_add_include_to_target(protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
|
||||
target_include_directories(protobuf-mutator PRIVATE ${INCLUDE_DIRECTORIES} ${PROTOBUF_MUT_INCLUDE_DIRS})
|
||||
target_include_directories(protobuf-mutator-libfuzzer PRIVATE ${INCLUDE_DIRECTORIES} ${PROTOBUF_MUT_INCLUDE_DIRS})
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# MSVC-specific compiler options
|
||||
target_compile_options(protobuf-mutator PRIVATE "/wd4244" "/wd4245" "/wd4267" "/wd4100" "/wd4456")
|
||||
|
@ -72,14 +73,68 @@ if (onnxruntime_FUZZ_ENABLED)
|
|||
# add all these include directory to the Fuzzing engine
|
||||
target_include_directories(onnxruntime_security_fuzz PRIVATE ${INCLUDE_FILES})
|
||||
|
||||
# add link libraries the project
|
||||
# add link libraries to the project
|
||||
target_link_libraries(onnxruntime_security_fuzz onnx_proto onnxruntime protobuf-mutator ${PROTOBUF_LIB})
|
||||
|
||||
# add the dependencies
|
||||
add_dependencies(onnxruntime_security_fuzz onnx_proto onnxruntime protobuf-mutator ${PROTOBUF_LIB})
|
||||
|
||||
# copy the dlls to the execution directory
|
||||
# copy the shared libraries (DLLs on Windows, SOs on Linux) to the execution directory
|
||||
add_custom_command(TARGET onnxruntime_security_fuzz POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_security_fuzz>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_security_fuzz>)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# Add a second fuzzer that uses libFuzzer in fuzzer/libfuzzer
|
||||
message(STATUS "Building libProtoBufFuzzer-based fuzzer")
|
||||
|
||||
# Set source files for the libFuzzer
|
||||
set(LIBFUZZER_SRC "${SEC_FUZZ_ROOT}/src/OnnxPrediction.cpp"
|
||||
"${SEC_FUZZ_ROOT}/src/testlog.cpp"
|
||||
"${SEC_FUZZ_ROOT}/ort_libfuzzer/OrtProtoLibfuzzer.cpp")
|
||||
|
||||
# Compile the libFuzzer-based fuzzer
|
||||
onnxruntime_add_executable(onnxruntime_proto_libfuzzer ${LIBFUZZER_SRC})
|
||||
# Security fuzzing engine header file reference
|
||||
onnxruntime_add_include_to_target(onnxruntime_proto_libfuzzer onnx onnxruntime)
|
||||
# Set include directories for libFuzzer
|
||||
target_include_directories(onnxruntime_proto_libfuzzer PRIVATE ${INCLUDE_FILES})
|
||||
|
||||
# Add link libraries for libFuzzer
|
||||
target_link_libraries(onnxruntime_proto_libfuzzer onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer -fsanitize=fuzzer,address ${PROTOBUF_LIB})
|
||||
|
||||
# Add the dependencies for libFuzzer
|
||||
add_dependencies(onnxruntime_proto_libfuzzer onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
|
||||
|
||||
# Copy shared libraries for libFuzzer
|
||||
add_custom_command(TARGET onnxruntime_proto_libfuzzer POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_proto_libfuzzer>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_proto_libfuzzer>)
|
||||
# Add a second fuzzer that uses libFuzzer in fuzzer/libfuzzer
|
||||
message(STATUS "Building libBufFuzzer-based fuzzer")
|
||||
|
||||
# Set source files for the libFuzzer
|
||||
set(LIBFUZZER_SRC "${SEC_FUZZ_ROOT}/src/OnnxPrediction.cpp"
|
||||
"${SEC_FUZZ_ROOT}/src/testlog.cpp"
|
||||
"${SEC_FUZZ_ROOT}/ort_libfuzzer/OrtLibfuzzer.cpp")
|
||||
|
||||
# Compile the libFuzzer-based fuzzer
|
||||
onnxruntime_add_executable(onnxruntime_libfuzzer_fuzz ${LIBFUZZER_SRC})
|
||||
# Security fuzzing engine header file reference
|
||||
onnxruntime_add_include_to_target(onnxruntime_libfuzzer_fuzz onnx onnxruntime)
|
||||
# Set include directories for libFuzzer
|
||||
target_compile_definitions(onnxruntime_libfuzzer_fuzz PRIVATE GOOGLE_PROTOBUF_NO_LOGGING=1)
|
||||
target_include_directories(onnxruntime_libfuzzer_fuzz PRIVATE ${INCLUDE_FILES})
|
||||
|
||||
# Add link libraries for libFuzzer
|
||||
target_link_libraries(onnxruntime_libfuzzer_fuzz onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer -fsanitize=fuzzer,address ${PROTOBUF_LIB})
|
||||
|
||||
# Add the dependencies for libFuzzer
|
||||
add_dependencies(onnxruntime_libfuzzer_fuzz onnx_proto onnxruntime protobuf-mutator protobuf-mutator-libfuzzer ${PROTOBUF_LIB})
|
||||
|
||||
# Copy shared libraries for libFuzzer
|
||||
add_custom_command(TARGET onnxruntime_libfuzzer_fuzz POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime> $<TARGET_FILE_DIR:onnxruntime_libfuzzer_fuzz>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${PROTOBUF_LIB}> $<TARGET_FILE_DIR:onnxruntime_libfuzzer_fuzz>)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "OnnxPrediction.h"
|
||||
#include "onnxruntime_session_options_config_keys.h"
|
||||
#include "src/libfuzzer/libfuzzer_macro.h"
|
||||
#include "fuzzer/FuzzedDataProvider.h"
|
||||
|
||||
Ort::Env env;
|
||||
|
||||
void predict(onnx::ModelProto& msg, unsigned int seed, Ort::Env& env) {
|
||||
// Create object for prediction
|
||||
//
|
||||
OnnxPrediction predict(msg, env);
|
||||
|
||||
// Give predict a function to generate the data
|
||||
// to run prediction on.
|
||||
//
|
||||
predict.SetupInput(GenerateDataForInputTypeTensor, seed);
|
||||
|
||||
// Run the prediction on the data
|
||||
//
|
||||
predict.RunInference();
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
FuzzedDataProvider data_provider(data, size);
|
||||
onnx::ModelProto msg;
|
||||
try {
|
||||
if (!msg.ParseFromArray(data, static_cast<int>(size))) {
|
||||
return 0; // Ignore invalid inputs
|
||||
}
|
||||
predict(msg, data_provider.ConsumeIntegral<int>(), env);
|
||||
} catch (const std::exception& e) {
|
||||
// Optionally log or suppress the exception
|
||||
// std::cerr << "Caught exception: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
// Handle any other exceptions
|
||||
// std::cerr << "Caught unknown exception." << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "src/mutator.h"
|
||||
#include "OnnxPrediction.h"
|
||||
#include "onnxruntime_session_options_config_keys.h"
|
||||
#include "src/libfuzzer/libfuzzer_macro.h"
|
||||
#include "onnx/onnx_pb.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
Ort::Env env;
|
||||
|
||||
std::string wstring_to_string(const std::wstring& wstr) {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
||||
return converter.to_bytes(wstr);
|
||||
}
|
||||
|
||||
void predict(onnx::ModelProto& msg, unsigned int seed, Ort::Env& env) {
|
||||
// Create object for prediction
|
||||
//
|
||||
OnnxPrediction predict(msg, env);
|
||||
|
||||
// Give predict a function to generate the data
|
||||
// to run prediction on.
|
||||
//
|
||||
predict.SetupInput(GenerateDataForInputTypeTensor, seed);
|
||||
|
||||
// Run the prediction on the data
|
||||
//
|
||||
predict.RunInference();
|
||||
|
||||
// View the output
|
||||
//
|
||||
predict.PrintOutputValues();
|
||||
}
|
||||
|
||||
template <class Proto>
|
||||
using PostProcessor =
|
||||
protobuf_mutator::libfuzzer::PostProcessorRegistration<Proto>;
|
||||
|
||||
// Helper function to generate random strings
|
||||
std::string generate_random_string(size_t length, std::mt19937& rng) {
|
||||
const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
std::uniform_int_distribution<> dist(0, characters.size() - 1);
|
||||
std::string result;
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
result += characters[dist(rng)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper function to generate random float
|
||||
float generate_random_float(std::mt19937& rng) {
|
||||
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
||||
return dist(rng);
|
||||
}
|
||||
|
||||
// PostProcessor for ONNX ModelProto with random values
|
||||
static PostProcessor<onnx::ModelProto> reg1 = {
|
||||
[](onnx::ModelProto* model_proto, unsigned int seed) {
|
||||
std::mt19937 rng(seed);
|
||||
|
||||
// Set model's IR version
|
||||
model_proto->set_ir_version(7);
|
||||
|
||||
model_proto->set_producer_name("onnx");
|
||||
model_proto->set_producer_version("7.0");
|
||||
model_proto->set_domain("example.com");
|
||||
|
||||
// Add a dummy opset import
|
||||
auto* opset_import = model_proto->add_opset_import();
|
||||
opset_import->set_version(10);
|
||||
|
||||
// Access the graph from the model
|
||||
auto* graph = model_proto->mutable_graph();
|
||||
|
||||
// Set a random name for the graph
|
||||
graph->set_name(generate_random_string(10, rng));
|
||||
}};
|
||||
|
||||
DEFINE_PROTO_FUZZER(const onnx::ModelProto& msg) {
|
||||
try {
|
||||
auto seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
|
||||
onnx::ModelProto msg_proto = msg;
|
||||
predict(msg_proto, seed, env);
|
||||
} catch (const std::exception& e) {
|
||||
// Optionally log or suppress the exception
|
||||
// std::cerr << "Caught exception: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
// Handle any other exceptions
|
||||
// std::cerr << "Caught unknown exception." << std::endl;
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче