| --- | |
| myst: | |
| substitutions: | |
| llvm_ir_fuzzer: '{ref}`structured LLVM IR fuzzer <fuzzing-llvm-ir>`' | |
| generic_fuzzer: '{ref}`generic fuzzer <fuzzing-llvm-generic>`' | |
| protobuf_fuzzer: '{ref}`libprotobuf-mutator based fuzzer <fuzzing-llvm-protobuf>`' | |
| --- | |
| # Fuzzing LLVM libraries and tools | |
| ## Introduction | |
| The LLVM tree includes a number of fuzzers for various components. These are | |
| built on top of {doc}`LibFuzzer <LibFuzzer>`. In order to build and run these | |
| fuzzers, see {ref}`building-fuzzers`. | |
| ## Available Fuzzers | |
| ### clang-fuzzer | |
| A {{ generic_fuzzer }} that tries to compile textual input as C++ code. Some of the | |
| bugs this fuzzer has reported are [on bugzilla](https://llvm.org/pr23057) and [on OSS Fuzz's | |
| tracker](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=proj-llvm+clang-fuzzer). | |
| ### clang-proto-fuzzer | |
| A {{ protobuf_fuzzer }} that compiles valid C++ programs generated from a protobuf | |
| class that describes a subset of the C++ language. | |
| This fuzzer accepts clang command-line options after `ignore_remaining_args=1`. | |
| For example, the following command will fuzz clang with a higher optimization | |
| level: | |
| ```shell | |
| % bin/clang-proto-fuzzer <corpus-dir> -ignore_remaining_args=1 -O3 | |
| ``` | |
| ### clang-format-fuzzer | |
| A {{ generic_fuzzer }} that runs [clang-format][clang-format] on C++ text fragments. Some of the | |
| bugs this fuzzer has reported are [on bugzilla](https://llvm.org/pr23052) | |
| and [on OSS Fuzz's tracker](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=proj-llvm+clang-format-fuzzer). | |
| ### llvm-as-fuzzer | |
| A {{ generic_fuzzer }} that tries to parse text as {doc}`LLVM assembly <LangRef>`. | |
| Some of the bugs this fuzzer has reported are [on bugzilla](https://llvm.org/pr24639). | |
| ### llvm-dwarfdump-fuzzer | |
| A {{ generic_fuzzer }} that interprets inputs as object files and runs | |
| {doc}`llvm-dwarfdump <CommandGuide/llvm-dwarfdump>` on them. Some of the bugs | |
| this fuzzer has reported are [on OSS Fuzz's tracker](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=proj-llvm+llvm-dwarfdump-fuzzer) | |
| ### llvm-demangle-fuzzer | |
| A {{ generic_fuzzer }} for the Itanium demangler used in various LLVM tools. We've | |
| fuzzed `__cxa_demangle` to death, why not fuzz LLVM's implementation of the same | |
| function! | |
| ### llvm-isel-fuzzer | |
| A {{ llvm_ir_fuzzer }} aimed at finding bugs in instruction selection. | |
| This fuzzer accepts flags after `ignore_remaining_args=1`. The flags match | |
| those of {doc}`llc <CommandGuide/llc>` and the triple is required. For example, | |
| the following command would fuzz AArch64 with {doc}`GlobalISel/index`: | |
| ```shell | |
| % bin/llvm-isel-fuzzer <corpus-dir> -ignore_remaining_args=1 -mtriple aarch64 -global-isel -O0 | |
| ``` | |
| Some flags can also be specified in the binary name itself in order to support | |
| OSS Fuzz, which has trouble with required arguments. To do this, you can copy | |
| or move `llvm-isel-fuzzer` to `llvm-isel-fuzzer--x-y-z`, separating options | |
| from the binary name using "--". The valid options are architecture names | |
| (`aarch64`, `x86_64`), optimization levels (`O0`, `O2`), or specific | |
| keywords, like `gisel` for enabling global instruction selection. In this | |
| mode, the same example could be run like so: | |
| ```shell | |
| % bin/llvm-isel-fuzzer--aarch64-O0-gisel <corpus-dir> | |
| ``` | |
| ### llvm-opt-fuzzer | |
| A {{ llvm_ir_fuzzer }} aimed at finding bugs in optimization passes. | |
| It receives an optimization pipeline and runs it for each fuzzer input. | |
| Interface of this fuzzer almost directly mirrors `llvm-isel-fuzzer`. Both | |
| `mtriple` and `passes` arguments are required. Passes are specified in a | |
| format suitable for the new pass manager. You can find some documentation about | |
| this format in the doxygen for `PassBuilder::parsePassPipeline`. | |
| ```shell | |
| % bin/llvm-opt-fuzzer <corpus-dir> -ignore_remaining_args=1 -mtriple x86_64 -passes instcombine | |
| ``` | |
| Similarly to the `llvm-isel-fuzzer`, arguments in some predefined configurations | |
| might be embedded directly into the binary file name: | |
| ```shell | |
| % bin/llvm-opt-fuzzer--x86_64-instcombine <corpus-dir> | |
| ``` | |
| ### llvm-mc-assemble-fuzzer | |
| A {{ generic_fuzzer }} that fuzzes the MC layer's assemblers by treating inputs as | |
| target-specific assembly. | |
| Note that this fuzzer has an unusual command line interface which is not fully | |
| compatible with all of libFuzzer's features. Fuzzer arguments must be passed | |
| after `--fuzzer-args`, and any `llc` flags must use two dashes. For | |
| example, to fuzz the AArch64 assembler you might use the following command: | |
| ```console | |
| llvm-mc-fuzzer --triple=aarch64-linux-gnu --fuzzer-args -max_len=4 | |
| ``` | |
| This scheme will likely change in the future. | |
| ### llvm-mc-disassemble-fuzzer | |
| A {{ generic_fuzzer }} that fuzzes the MC layer's disassemblers by treating inputs | |
| as assembled binary data. | |
| Note that this fuzzer has an unusual command line interface which is not fully | |
| compatible with all of libFuzzer's features. See the notes above about | |
| `llvm-mc-assemble-fuzzer` for details. | |
| ### lldb-target-fuzzer | |
| A {{ generic_fuzzer }} that interprets inputs as object files and uses them to | |
| create a target in lldb. | |
| ## Mutators and Input Generators | |
| The inputs for a fuzz target are generated via random mutations of a | |
| {ref}`corpus <libfuzzer-corpus>`. There are a few options for the kinds of | |
| mutations that a fuzzer in LLVM might want. | |
| (fuzzing-llvm-generic)= | |
| ### Generic Random Fuzzing | |
| The most basic form of input mutation is to use the built-in mutators of | |
| LibFuzzer. These simply treat the input corpus as a bag of bits and make random | |
| mutations. This type of fuzzer is good for stressing the surface layers of a | |
| program, and is good at testing things like lexers, parsers, or binary | |
| protocols. | |
| Some of the in-tree fuzzers that use this type of mutator are [clang-fuzzer](#clang-fuzzer), | |
| [clang-format-fuzzer](#clang-format-fuzzer), [llvm-as-fuzzer](#llvm-as-fuzzer), [llvm-dwarfdump-fuzzer](#llvm-dwarfdump-fuzzer), | |
| [llvm-mc-assemble-fuzzer](#llvm-mc-assemble-fuzzer), and [llvm-mc-disassemble-fuzzer](#llvm-mc-disassemble-fuzzer). | |
| (fuzzing-llvm-protobuf)= | |
| ### Structured Fuzzing using `libprotobuf-mutator` | |
| We can use [libprotobuf-mutator][libprotobuf-mutator] in order to perform structured fuzzing and | |
| stress deeper layers of programs. This works by defining a protobuf class that | |
| translates arbitrary data into structurally interesting input. Specifically, we | |
| use this to work with a subset of the C++ language and perform mutations that | |
| produce valid C++ programs in order to exercise parts of clang that are more | |
| interesting than parser error handling. | |
| To build this kind of fuzzer you need [protobuf][protobuf] and its dependencies | |
| installed, and you need to specify some extra flags when configuring the build | |
| with {doc}`CMake <CMake>`. For example, [clang-proto-fuzzer](#clang-proto-fuzzer) can be enabled by | |
| adding `-DCLANG_ENABLE_PROTO_FUZZER=ON` to the flags described in | |
| {ref}`building-fuzzers`. | |
| The only in-tree fuzzer that uses `libprotobuf-mutator` today is | |
| [clang-proto-fuzzer](#clang-proto-fuzzer). | |
| (fuzzing-llvm-ir)= | |
| ### Structured Fuzzing of LLVM IR | |
| We also use a more direct form of structured fuzzing for fuzzers that take | |
| {doc}`LLVM IR <LangRef>` as input. This is achieved through the `FuzzMutate` | |
| library, which was [discussed at EuroLLVM 2017][discussed at eurollvm 2017]. | |
| The `FuzzMutate` library is used to structurally fuzz backends in | |
| [llvm-isel-fuzzer](#llvm-isel-fuzzer). | |
| ## Building and Running | |
| (building-fuzzers)= | |
| ### Configuring LLVM to Build Fuzzers | |
| Fuzzers will be built and linked to libFuzzer by default as long as you build | |
| LLVM with sanitizer coverage enabled. You would typically also enable at least | |
| one sanitizer to find bugs faster. The most common way to build the fuzzers is | |
| by adding the following two flags to your CMake invocation: | |
| `-DLLVM_USE_SANITIZER=Address -DLLVM_USE_SANITIZE_COVERAGE=On`. | |
| :::{note} | |
| If you have `compiler-rt` checked out in an LLVM tree when building | |
| with sanitizers, you'll want to specify `-DLLVM_BUILD_RUNTIME=Off` | |
| to avoid building the sanitizers themselves with sanitizers enabled. | |
| ::: | |
| :::{note} | |
| You may run into issues if you build with BFD ld, which is the | |
| default linker on many Unix systems. These issues are being tracked | |
| in <https://llvm.org/PR34636>. | |
| ::: | |
| ### Continuously Running and Finding Bugs | |
| There used to be a public buildbot running LLVM fuzzers continuously, and while | |
| this did find issues, it didn't have a very good way to report problems in an | |
| actionable way. Because of this, we're moving towards using [OSS Fuzz][oss fuzz] more | |
| instead. | |
| You can browse the [LLVM project issue list][llvm project issue list] for the bugs found by | |
| [LLVM on OSS Fuzz][llvm on oss fuzz]. These are also mailed to the [llvm-bugs mailing | |
| list][llvm-bugs mailing list]. | |
| ## Utilities for Writing Fuzzers | |
| There are some utilities available for writing fuzzers in LLVM. | |
| Some helpers for handling the command line interface are available in | |
| `include/llvm/FuzzMutate/FuzzerCLI.h`, including functions to parse command | |
| line options in a consistent way and to implement standalone main functions so | |
| your fuzzer can be built and tested when not built against libFuzzer. | |
| There is also some handling of the CMake config for fuzzers, where you should | |
| use the `add_llvm_fuzzer` to set up fuzzer targets. This function works | |
| similarly to functions such as `add_llvm_tool`, but it takes care of linking | |
| to LibFuzzer when appropriate and can be passed the `DUMMY_MAIN` argument to | |
| enable standalone testing. | |
| [clang-format]: https://clang.llvm.org/docs/ClangFormat.html | |
| [discussed at eurollvm 2017]: https://www.youtube.com/watch?v=UBbQ_s6hNgg | |
| [libprotobuf-mutator]: https://github.com/google/libprotobuf-mutator | |
| [llvm on oss fuzz]: https://github.com/google/oss-fuzz/blob/master/projects/llvm | |
| [llvm project issue list]: https://bugs.chromium.org/p/oss-fuzz/issues/list?q=Proj-llvm | |
| [llvm-bugs mailing list]: http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs | |
| [oss fuzz]: https://github.com/google/oss-fuzz | |
| [protobuf]: https://github.com/google/protobuf |