diff --git a/.circleci/config.yml b/.circleci/config.yml index 0224ac93b..6a7a03a61 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -91,7 +91,9 @@ defaults: paths: - test/tools/ossfuzz/abiv2_proto_ossfuzz - test/tools/ossfuzz/const_opt_ossfuzz + - test/tools/ossfuzz/solc_noopt_mutator_ossfuzz - test/tools/ossfuzz/solc_noopt_ossfuzz + - test/tools/ossfuzz/solc_opt_mutator_ossfuzz - test/tools/ossfuzz/solc_opt_ossfuzz - test/tools/ossfuzz/strictasm_assembly_ossfuzz - test/tools/ossfuzz/strictasm_diff_ossfuzz diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt index beab9e79c..a6d4addc1 100644 --- a/test/tools/ossfuzz/CMakeLists.txt +++ b/test/tools/ossfuzz/CMakeLists.txt @@ -1,12 +1,14 @@ add_custom_target(ossfuzz) add_dependencies(ossfuzz solc_opt_ossfuzz + solc_opt_mutator_ossfuzz solc_noopt_ossfuzz + solc_noopt_mutator_ossfuzz const_opt_ossfuzz strictasm_diff_ossfuzz strictasm_opt_ossfuzz strictasm_assembly_ossfuzz - ) +) if (OSSFUZZ) @@ -31,6 +33,16 @@ if (OSSFUZZ) target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm) set_target_properties(solc_opt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) + add_executable(solc_opt_mutator_ossfuzz + solc_opt_ossfuzz.cpp + ../fuzzer_common.cpp + ../../TestCaseReader.cpp + SolidityGenerator.cpp + SolidityCustomMutatorInterface.cpp + ) + target_link_libraries(solc_opt_mutator_ossfuzz PRIVATE libsolc evmasm) + set_target_properties(solc_opt_mutator_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) + add_executable(solc_noopt_ossfuzz solc_noopt_ossfuzz.cpp ../fuzzer_common.cpp @@ -39,6 +51,16 @@ if (OSSFUZZ) target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm) set_target_properties(solc_noopt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) + add_executable(solc_noopt_mutator_ossfuzz + solc_noopt_ossfuzz.cpp + ../fuzzer_common.cpp + ../../TestCaseReader.cpp + SolidityGenerator.cpp + SolidityCustomMutatorInterface.cpp + ) + target_link_libraries(solc_noopt_mutator_ossfuzz PRIVATE libsolc evmasm) + set_target_properties(solc_noopt_mutator_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) + add_executable(const_opt_ossfuzz const_opt_ossfuzz.cpp ../fuzzer_common.cpp) target_link_libraries(const_opt_ossfuzz PRIVATE libsolc evmasm) set_target_properties(const_opt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) @@ -82,14 +104,14 @@ if (OSSFUZZ) protoToYul.cpp yulProto.pb.cc protomutators/YulProtoMutator.cpp -) + ) target_include_directories(yul_proto_diff_custom_mutate_ossfuzz PRIVATE /usr/include/libprotobuf-mutator) target_link_libraries(yul_proto_diff_custom_mutate_ossfuzz PRIVATE yul yulInterpreter protobuf-mutator-libfuzzer.a protobuf-mutator.a protobuf.a -) + ) set_target_properties(yul_proto_diff_custom_mutate_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) target_compile_options(yul_proto_diff_custom_mutate_ossfuzz PUBLIC ${COMPILE_OPTIONS} -Wno-sign-conversion) @@ -139,12 +161,24 @@ else() ) target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm) + add_library(solc_opt_mutator_ossfuzz + solc_opt_ossfuzz.cpp + ../fuzzer_common.cpp + ) + target_link_libraries(solc_opt_mutator_ossfuzz PRIVATE libsolc evmasm) + add_library(solc_noopt_ossfuzz solc_noopt_ossfuzz.cpp ../fuzzer_common.cpp ) target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm) + add_library(solc_noopt_mutator_ossfuzz + solc_noopt_ossfuzz.cpp + ../fuzzer_common.cpp + ) + target_link_libraries(solc_noopt_mutator_ossfuzz PRIVATE libsolc evmasm) + add_library(const_opt_ossfuzz const_opt_ossfuzz.cpp ../fuzzer_common.cpp) diff --git a/test/tools/ossfuzz/SolidityCustomMutatorInterface.cpp b/test/tools/ossfuzz/SolidityCustomMutatorInterface.cpp new file mode 100644 index 000000000..ac56860b9 --- /dev/null +++ b/test/tools/ossfuzz/SolidityCustomMutatorInterface.cpp @@ -0,0 +1,69 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include +#include + +#include + +using namespace std; +using namespace solidity::test::fuzzer; + +namespace +{ +/// Forward declare libFuzzer's default mutator definition +extern "C" size_t LLVMFuzzerMutate(uint8_t* _data, size_t _size, size_t _maxSize); + +/// Define Solidity's custom mutator by implementing libFuzzer's +/// custom mutator external interface. +extern "C" size_t LLVMFuzzerCustomMutator( + uint8_t* _data, + size_t _size, + size_t _maxSize, + unsigned int _seed +) +{ + if (_maxSize <= _size || _size == 0) + return LLVMFuzzerMutate(_data, _size, _maxSize); + return SolidityCustomMutatorInterface{_data, _size, _maxSize, _seed}.generate(); +} +} + +SolidityCustomMutatorInterface::SolidityCustomMutatorInterface( + uint8_t* _data, + size_t _size, + size_t _maxSize, + unsigned int _seed + ): + data(_data), + size(_size), + maxMutantSize(_maxSize), + generator(make_shared(_seed)) +{} + +size_t SolidityCustomMutatorInterface::generate() +{ + string testCase = generator->generateTestProgram(); + solAssert( + !testCase.empty() && data, + "Solc custom mutator: Invalid mutant or memory pointer" + ); + size_t mutantSize = min(testCase.size(), maxMutantSize - 1); + mempcpy(data, testCase.data(), mutantSize); + return mutantSize; +} diff --git a/test/tools/ossfuzz/SolidityCustomMutatorInterface.h b/test/tools/ossfuzz/SolidityCustomMutatorInterface.h new file mode 100644 index 000000000..2b7be6cc5 --- /dev/null +++ b/test/tools/ossfuzz/SolidityCustomMutatorInterface.h @@ -0,0 +1,46 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Implements libFuzzer's custom mutator interface. + */ + +#pragma once + +#include + +#include + +namespace solidity::test::fuzzer +{ +struct SolidityCustomMutatorInterface +{ + SolidityCustomMutatorInterface(uint8_t* _data, size_t _size, size_t _maxSize, unsigned _seed); + /// Generates Solidity test program, copies it into buffer + /// provided by libFuzzer and @returns size of the test program. + size_t generate(); + + /// Raw pointer to libFuzzer provided input + uint8_t* data; + /// Size of libFuzzer provided input + size_t size; + /// Maximum length of mutant specified by libFuzzer + size_t maxMutantSize; + /// Solidity generator handle + std::shared_ptr generator; +}; +} diff --git a/test/tools/ossfuzz/SolidityGenerator.cpp b/test/tools/ossfuzz/SolidityGenerator.cpp new file mode 100644 index 000000000..f9c43ef66 --- /dev/null +++ b/test/tools/ossfuzz/SolidityGenerator.cpp @@ -0,0 +1,35 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +using namespace solidity::test::fuzzer; +using namespace solidity::util; +using namespace std; + +string SolidityGenerator::generateTestProgram() +{ + // TODO: Add generators for grammar elements of + // Solidity antlr4 grammar. Currently, the generated + // test program consists of a version pragma only. + return Whiskers(R"(pragma ;)") + ("directive", "solidity >= 0.0.0") + .render(); +} \ No newline at end of file diff --git a/test/tools/ossfuzz/SolidityGenerator.h b/test/tools/ossfuzz/SolidityGenerator.h new file mode 100644 index 000000000..5b7abce04 --- /dev/null +++ b/test/tools/ossfuzz/SolidityGenerator.h @@ -0,0 +1,42 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Implements generators for synthesizing mostly syntactically valid + * Solidity test programs. + */ + +#pragma once + +#include + +namespace solidity::test::fuzzer +{ +using RandomEngine = std::mt19937_64; + +class SolidityGenerator +{ +public: + SolidityGenerator(uint64_t _seed): m_rand(_seed) + {} + /// @returns a pseudo randomly generated test program + std::string generateTestProgram(); +private: + /// Random number generator + RandomEngine const m_rand; +}; +} \ No newline at end of file