From: Chelsea Cassanova Date: Mon, 11 Jul 2022 21:24:50 +0000 (-0400) Subject: [lldb/Fuzzer] Add fuzzer for expression evaluator X-Git-Tag: upstream/15.0.7~747 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b797834748f1954950880bf50fb78abedd4494e6;p=platform%2Fupstream%2Fllvm.git [lldb/Fuzzer] Add fuzzer for expression evaluator This commit adds a fuzzer for LLDB's expression evaluator. The fuzzer takes a different approach than the current fuzzers present, and uses an approach that is currently being used for clang fuzzers. Instead of fuzzing the evaluator with randomly mutated characters, protobufs are used to generate a subset of C++. This is then converted to valid C++ code and sent to the expression evaluator. In addition, libprotobuf_mutator is used to mutate the fuzzer's inputs from valid C++ code to valid C++ code, rather than mutating from valid code to total nonsense. Differential revision: https://reviews.llvm.org/D129377 --- diff --git a/clang/cmake/modules/ProtobufMutator.cmake b/clang/cmake/modules/ProtobufMutator.cmake index 15fe95e..071f11b 100644 --- a/clang/cmake/modules/ProtobufMutator.cmake +++ b/clang/cmake/modules/ProtobufMutator.cmake @@ -1,5 +1,9 @@ include(ExternalProject) -set(PBM_PREFIX protobuf_mutator) + +if (NOT PBM_PREFIX) + set (PBM_PREFIX protobuf_mutator) +endif() + set(PBM_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PBM_PREFIX}/src/${PBM_PREFIX}) set(PBM_LIB_PATH ${PBM_PATH}-build/src/libprotobuf-mutator.a) set(PBM_FUZZ_LIB_PATH ${PBM_PATH}-build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a) diff --git a/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt b/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt index 6d62421..469b88c 100644 --- a/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt +++ b/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt @@ -11,3 +11,5 @@ add_clang_library(clangHandleCXX clangSerialization clangTooling ) + +target_include_directories(clangHandleCXX PUBLIC .) diff --git a/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt b/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt index 339959b..45f51c9 100644 --- a/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt +++ b/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt @@ -14,6 +14,8 @@ add_clang_library(clangLoopProtoToCXX loop_proto_to_cxx.cpp DEPENDS clangCXXLoopProto LINK_LIBS clangCXXLoopProto ${PROTOBUF_LIBRARIES} ) +target_include_directories(clangProtoToCXX PUBLIC .) +target_include_directories(clangLoopProtoToCXX PUBLIC .) add_clang_executable(clang-proto-to-cxx proto_to_cxx_main.cpp) add_clang_executable(clang-loop-proto-to-cxx loop_proto_to_cxx_main.cpp) diff --git a/lldb/tools/lldb-fuzzer/CMakeLists.txt b/lldb/tools/lldb-fuzzer/CMakeLists.txt index 867a419..4c081a9 100644 --- a/lldb/tools/lldb-fuzzer/CMakeLists.txt +++ b/lldb/tools/lldb-fuzzer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(lldb-commandinterpreter-fuzzer) +add_subdirectory(lldb-expression-fuzzer) add_subdirectory(lldb-target-fuzzer) add_subdirectory(utils) diff --git a/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/CMakeLists.txt b/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/CMakeLists.txt new file mode 100644 index 0000000..40606f1 --- /dev/null +++ b/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/CMakeLists.txt @@ -0,0 +1,57 @@ +if(CLANG_ENABLE_PROTO_FUZZER) + set(LLVM_LINK_COMPONENTS + Support + ) + + add_llvm_fuzzer(lldb-expression-fuzzer + EXCLUDE_FROM_ALL + lldb-expression-fuzzer.cpp + ) + + if(TARGET lldb-expression-fuzzer) + target_include_directories(lldb-expression-fuzzer PRIVATE ..) + find_package(Protobuf REQUIRED) + add_definitions(-DGOOGLE_PROTOBUF_NO_RTTI) + include_directories(${PROTOBUF_INCLUDE_DIRS}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../../clang/tools/clang-fuzzer PRIVATE ..) + + set(CLANG_CMAKE_MODULE_PATH + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../clang/cmake/modules) + + set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + ${CLANG_CMAKE_MODULE_PATH}) + + + set (PBM_PREFIX lldb_protobuf_mutator) + include(ProtobufMutator) + include_directories(${ProtobufMutator_INCLUDE_DIRS}) + + target_link_libraries(lldb-expression-fuzzer + PRIVATE + ${ProtobufMutator_LIBRARIES} + ${LLVM_LIB_FUZZING_ENGINE} + clangHandleCXX + clangCXXProto + clangProtoToCXX + liblldb + ) + + add_custom_command(TARGET lldb-expression-fuzzer PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/fuzzer-artifacts/expression-artifacts + # Create and compile a simple C program using the command line. This is + # needed because LLDB's expression evaluator needs a legitmate target + # instead of a dummy target + COMMAND echo 'int main (int argc, char** argv) { return 0\; }' | clang -o main.out -xc - + ) + + # Create a directory for storing the fuzzer's artifacts and run the fuzzer with arguments that will + # not attempt to reduce the size of the inputs being generated + add_custom_target(fuzz-lldb-expression + COMMENT "Running the LLDB expression evaluator fuzzer..." + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/fuzzer-artifacts/expression-artifacts + COMMAND $ -artifact_prefix=expression- -reduce_inputs=0 + USES_TERMINAL + ) + endif() +endif() diff --git a/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/lldb-expression-fuzzer.cpp b/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/lldb-expression-fuzzer.cpp new file mode 100644 index 0000000..03750e4 --- /dev/null +++ b/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/lldb-expression-fuzzer.cpp @@ -0,0 +1,73 @@ +//===-- lldb-expression-fuzzer.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// \file +// This file is a fuzzer for LLDB's expression evaluator. It uses protobufs +// and the libprotobuf-mutator to create valid C-like inputs for the +// expression evaluator. +// +//===---------------------------------------------------------------------===// + +#include + +#include "cxx_proto.pb.h" +#include "handle_cxx.h" +#include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBTarget.h" +#include "proto_to_cxx.h" +#include "src/libfuzzer/libfuzzer_macro.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +using namespace lldb; +using namespace llvm; +using namespace clang_fuzzer; + +char **originalargv; + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + SBDebugger::Initialize(); + + // The path for a simple compiled program is needed to create a + // target for the debugger and that path is passed in through argv + originalargv = *argv; + return 0; +} + +DEFINE_BINARY_PROTO_FUZZER(const clang_fuzzer::Function &input) { + auto input_string = clang_fuzzer::FunctionToString(input); + + // Get the second argument from argv and strip the '--' from it. + // This will be used as the path for the object file to create a target from + std::string raw_path = originalargv[2]; + StringRef obj_path = raw_path.erase(0, 2); + + // Create a debugger and a target + SBDebugger debugger = SBDebugger::Create(false); + SBTarget target = debugger.CreateTarget(obj_path.str().c_str()); + + // Create a breakpoint on the only line in the program + SBBreakpoint breakpoint = target.BreakpointCreateByLocation(obj_path.str().c_str(), 1); + + // Create launch info and error for launching the process + SBLaunchInfo launch_info = target.GetLaunchInfo(); + SBError error; + + // Launch the process and evaluate the fuzzer's input data + // as an expression + SBProcess process = target.Launch(launch_info, error); + target.EvaluateExpression(input_string.c_str()); + + debugger.DeleteTarget(target); + SBDebugger::Destroy(debugger); + SBModule::GarbageCollectAllocatedModules(); +}