| # Build a fuzzer |
| |
| This guide assumes you have already [created](write-a-fuzzer.md) a fuzzer that you now want to |
| build. It uses the same [sample code](write-a-fuzzer.md#samples) as in that guide. |
| |
| Fuchsia uses [GN][fuchsia-gn], a meta-build system, to generate `.ninja` files that explicitly |
| describe how to build the system. [_GN targets_][gn-targets]{: .external} are nodes in the build graph |
| that represent a specific output such as a library or executable. |
| [_GN templates_][gn-templates]{: .external} are rules that generate additional targets. |
| |
| In order to make adding new fuzzers as easy as possible, Fuchsia provides fuzzing-related GN |
| templates. |
| |
| * To create build rules for a fuzzer binary for Fuchsia, see the |
| [Fuchsia library fuzzer GN template](#fuchsia-library-fuzzer) for the appropriate language. |
| * To create build rules for a fuzzer binary for your development host, see the |
| [Host library fuzzer GN template](#host-library-fuzzer) |
| * To create build rules for a fuzzer component, see |
| [Fuchsia fuzzer component GN template](#fuchsia-fuzzer-component). |
| * To create build rules for a package of fuzzer binaries, see |
| [Fuchsia fuzzer package GN template](#fuchsia-fuzzer-package). |
| |
| Once you have defined your build rules, you can [build fuzzers with fx](#fx-set). |
| |
| ## Fuchsia library fuzzer GN template {#fuchsia-library-fuzzer} |
| |
| Each language has a specific fuzzer GN template: |
| |
| * {C/C++} |
| The [`fuchsia_library_fuzzer`][fuchsia_library_fuzzer.gni] GN template generates an `executable` |
| target that compiles and links the fuzz target function with the code under test and the fuzzing |
| engine. |
| |
| To create build rules for a C or C++ fuzzer, add a `fuchsia_library_fuzzer` GN target to an |
| appropriate BUILD.gn, such as the one with the corresponding unit test rules. |
| |
| For example: |
| |
| ```gn |
| import("//build/fuzz.gni") |
| |
| fuchsia_library_fuzzer("parser-fuzzer") { |
| sources = [ "parser_fuzzer.cc" ] |
| deps = [ ":parser-lib" ] |
| } |
| ``` |
| |
| * {Rust} |
| |
| The [`rustc_fuzzer`][rustc_fuzzer.gni] GN template generates a GN target that compiles the Rust |
| fuzz target function into a C object file that it then links with the fuzzing engine. |
| |
| To create build rules for a Rust fuzzer, add a `rustc_fuzzer` GN target to the crate's BUILD.gn. |
| |
| When choosing where and how to add this target, consider the following: |
| |
| * It is recommended to have the fuzzer name match the fuzz target function name, and to include |
| the fuzz target function in a Rust library, i.e. in `src/lib.rs`. You may leave the body of the |
| template empty when following these recommendations. For example, using the |
| `toy_example_arbitrary` [example](write-a-fuzzer.md#advanced), you would add the following to |
| your `BUILD.gn`: |
| |
| ```gn |
| import("//build/rust/rustc_fuzzer.gni") |
| |
| rustc_fuzzer("toy_example_arbitrary") { |
| } |
| ``` |
| |
| * If the fuzz target function name differs from the fuzzer name, you must provide it with the |
| `rustfunction` parameter. For example, using the `toy_example_u8` |
| [example](write-a-fuzzer.md#basic), you would add the following to your `BUILD.gn`: |
| |
| ```gn |
| import("//build/rust/rustc_fuzzer.gni") |
| |
| rustc_fuzzer("toy_example_raw_bytes") { |
| rustfunction = "toy_example_u8" |
| } |
| ``` |
| |
| * If the code to be tested cannot be easily factored into a library, a Rust binary can be used |
| with two additional steps: |
| |
| * You must exclude the `main` function from compilation, along with any items not used when |
| fuzzing, e.g. imports only used in `main`. For example: |
| |
| ```rust |
| #[cfg(not(fuzz))] |
| use only::used::in::main; |
| |
| #[cfg(not(fuzz))] |
| fn main() { ... } |
| ``` |
| |
| * You must explicitly provide the fuzz target function to the `rustc_fuzzer` with the |
| `source_root` parameter. For example, in your `BUILD.gn`: |
| |
| ```gn |
| import("//build/rust/rustc_fuzzer.gni") |
| |
| rustc_fuzzer("toy_example_with_main") { |
| source_root = "src/main.rs" |
| } |
| ``` |
| |
| When a [fuzzing variant][variants] is [selected](#fx-set), these templates will build a fuzzer |
| binary by linking the \[libFuzzer\] compiler runtime with the provided `sources`, `deps` or both. This |
| code must provide a [fuzz target][fuzz-target]{:.external} function. |
| |
| Otherwise, a fuzzer unit test is built by linking a [test harness][test-harness] with the provided |
| code. This test harness calls the fuzz target function with fixed inputs, such |
| as a zero length input. This test ensures the fuzzer can compile and link, even when not building |
| for fuzzing. |
| |
| Note: Since the generated unit test uses a zero-length input, your fuzzer _must not_ crash when |
| provided with a zero-length input. If a fuzzer input is shorter than your fuzzer's minimum input |
| length, you can simply return early. |
| |
| ## Host library fuzzer GN template {#host-library-fuzzer} |
| |
| You can also build fuzzers that run on your development host using the Fuchsia build system. |
| To build host fuzzers, use the [`host_library_fuzzer`][host_library_fuzzer.gni] GN template. |
| |
| For example: |
| |
| ```gn |
| host_library_fuzzer("my_host_fuzzer") { |
| sources = [ ... ] |
| deps = [ ... ] |
| } |
| ``` |
| |
| Host fuzzers can be built using [`fx`](#fx-set) without adding them to a Fuchsia component or |
| package. |
| |
| ## Fuchsia fuzzer component GN template {#fuchsia-fuzzer-component} |
| |
| The `fuchsia_fuzzer_component` [template][fuchsia_fuzzer_component.gni] creates a component used to |
| run the fuzzer. It can include the usual component parameters, such as `component_name` and `deps`. |
| |
| For example: |
| |
| ```gn |
| fuchsia_fuzzer_component("my-fuzzer-component") { |
| component_name = "my-fuzzer" |
| manifest = "meta/my-fuzzer.cml" |
| deps = [ ":my-corpus"] |
| } |
| ``` |
| |
| The [component manifest source][glossary.manifest] for library fuzzers must include |
| the default shard for libfuzzer. The output name of the fuzzer must be |
| provided as the first program argument as a package-relative path. Additional arguments may include |
| libFuzzer [options][options]{:.external}, or package-relative paths to directories of seed inputs |
| known as [seed corpora][corpus]{:.external}. |
| |
| For example: |
| |
| ``` |
| { |
| include: [ |
| "//sdk/lib/inspect/client.shard.cml", |
| "//src/sys/fuzzing/libfuzzer/default.shard.cml", |
| "//src/sys/test_runners/fuzz/default.shard.cml", |
| "//src/sys/test_runners/tmp_storage.shard.cml", |
| "syslog/client.shard.cml", |
| ] |
| program: { |
| args: [ |
| "test/my-fuzzer", |
| "-max_input_size=256", |
| "data/my-corpus", |
| ] |
| } |
| } |
| ``` |
| |
| A seed corpus should match a `resource` target that is included in the component's |
| `deps`. |
| |
| For example: |
| |
| ```gn |
| {% verbatim %} |
| import("//build/dist/resource.gni") |
| |
| resource("my-corpus") { |
| sources = [ |
| "input0", |
| "input1", |
| "input2", |
| ] |
| outputs = [ "data/my-corpus/{{source_file_part}}" ] |
| } |
| {% endverbatim %} |
| ``` |
| |
| ## Fuchsia fuzzer package GN template {#fuchsia-fuzzer-package} |
| |
| The `fuchsia_fuzzer_package` [template][fuzzer_package.gni] bundles fuzzer components into a |
| Fuchsia [package][glossary.package], similar to how `fuchsia_test_package` bundles test components. |
| The `fuchsia_fuzzer_package` template is distinguished by adding a specific build rule |
| to annotate fuzzers when built by a fuzzing toolchain [variant][variants]. |
| |
| Note: Executables built by these templates are only be capable of fuzzing if they are selected by a |
| fuzzing toolchain variant. If they are built by another toolchain, they only test a fixed set of |
| inputs. See [Build fuzzers with fx](#fx-set) for more details. |
| |
| The template includes parameters that are lists of fuzzer components, organized by language. Each |
| language has a set of supported sanitizers provided by their toolchain as compiler runtimes. |
| When the selected toolchain variant includes a sanitizer that is supported for a given language, the |
| corresponding list of fuzzer components are capable of fuzzing. |
| |
| For example, if the C++ toolchain has support for a hypotheical _examplesan_, the Rust toolchain |
| does not, and the _examplesan-fuzzer_ variant is selected, then the package definition below builds |
| `my-cpp-fuzzer` for fuzzing and `my-rust-fuzzer` for testing only. |
| |
| ```gn |
| fuchsia_fuzzer_package("my-fuzzers") { |
| cpp_fuzz_components = [ ":my-cpp-fuzzer" ] |
| rust_fuzz_components = [ ":my-rust-fuzzer" ] |
| } |
| ``` |
| |
| It is not necessary to include a list if the package has no fuzzers written in the corresponding |
| languages. |
| |
| A `fuchsia_fuzzer_package` can use all the same parameters as a [`fuchsia_package`][gn-package]. |
| |
| For example: |
| |
| ```gn |
| fuchsia_fuzzer_package("my-fuzzers") { |
| package_name = "the-fuzzers" |
| cpp_fuzz_components = [ ":my-fuzzer" ] |
| } |
| ``` |
| |
| Once defined, a package needs to be included in the build dependency graph like any other test |
| package. This typically means adding it to a group of tests. |
| |
| For example: |
| |
| ```gn |
| group("tests") { |
| deps = [ |
| ":my-test-package", |
| ":my-fuzzers", |
| ] |
| } |
| ``` |
| |
| ## Build fuzzers with `fx` {#fx-set} |
| |
| As noted above, the Fuchsia build system will build the fuzzers _only_ if it is explicitly told to |
| instrument them for fuzzing with an appropriate fuzzing variant. These are the |
| [known variants][known_variants] that end in `-fuzzer`. Each one is an extension of a |
| [sanitizer][sanitizers]{:.external} variant, including: |
| |
| * _asan_: Use [AddressSanitizer][asan]{:.external} to detect memory errors such as using memory |
| after [freeing][asan-uaf]{:.external} or [returning][asan-uar]{:.external} it, overflowing |
| [heap][asan-hbo]{:.external} and [stack][asan-sbo]{:.external} buffer overflows, and more. |
| * _ubsan_: Use [UndefinedBehaviorSanitizer][ubsan]{:.external} to detect behavior that violates the |
| language specification such as [signed integer overflow][ubsan-sio]{:.external}, misaligned |
| pointers, and [more][ubsan-all]{:.external}. |
| |
| The easiest way to build a `fuzzer_package` with a fuzzing variant is to use the |
| `--fuzz-with <sanitizer>` flag with [`fx set`][fx-set]. |
| |
| For example: |
| |
| <pre> |
| <code class="devsite-terminal">fx set core.x64 --fuzz-with asan --with //bundles/tests</code> |
| <code class="devsite-terminal">fx build</code> |
| </pre> |
| |
| Note: In some situations, Ninja cannot determine when an output needs to be rebuilt as a result of |
| compiler configuration changes. If building fails, try [`fx clean-build`][fx-build]. |
| |
| After running `fx set`, you can view the currently configured fuzzers with `ffx fuzz list`. |
| Additional `ffx fuzz` commands can be used to [run a fuzzer](run-a-fuzzer.md). |
| |
| [glossary.package]: /docs/glossary/README.md#package |
| [glossary.manifest]: /docs/glossary/README.md#component-manifest-source |
| [asan]: https://clang.llvm.org/docs/AddressSanitizer.html |
| [asan-hbo]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleHeapOutOfBounds |
| [asan-sbo]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleStackOutOfBounds |
| [asan-uaf]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleUseAfterFree |
| [asan-uar]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleUseAfterReturn |
| [corpus]: https://llvm.org/docs/LibFuzzer.html#corpus |
| [fuchsia-gn]: /docs/development/build/build_system/intro.md |
| [fuchsia_library_fuzzer.gni]: /build/fuzzing/fuchsia_library_fuzzer.gni |
| [fuchsia_fuzzer_component.gni]: /build/fuzzing/fuchsia_fuzzer_component.gni |
| [fuzz-target]: https://llvm.org/docs/LibFuzzer.html#fuzz-target |
| [fuzzer_package.gni]: /build/fuzzing/fuchsia_fuzzer_package.gni |
| [fx-build]: /docs/development/build/fx.md#execute-a-build |
| [fx-set]: /docs/development/build/fx.md#configure-a-build |
| [gn-package]: /docs/development/components/build.md |
| [gn-targets]: https://gn.googlesource.com/gn/+/HEAD/docs/language.md#Targets |
| [gn-templates]: https://gn.googlesource.com/gn/+/HEAD/docs/language.md#Templates |
| [host_library_fuzzer.gni]: /build/fuzzing/host_library_fuzzer.gni |
| [known_variants]: /docs/gen/build_arguments.md#known_variants |
| [options]: https://llvm.org/docs/LibFuzzer.html#options |
| [rustc_fuzzer.gni]: /build/rust/rustc_fuzzer.gni |
| [sanitizers]: https://github.com/google/sanitizers/wiki |
| [test-harness]: /src/lib/fuzzing/cpp/fuzzer_test.cc |
| [ubsan]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html |
| [ubsan-sio]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#usage |
| [ubsan-all]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks |
| [variants]: /docs/development/build/build_system/variants.md |