mirror of https://github.com/google/oss-fuzz.git
270 lines
11 KiB
Markdown
270 lines
11 KiB
Markdown
---
|
|
layout: default
|
|
parent: ClusterFuzzLite
|
|
title: Build Integration
|
|
has_children: true
|
|
nav_order: 2
|
|
permalink: /clusterfuzzlite/build-integration/
|
|
---
|
|
# Build integration
|
|
{: .no_toc}
|
|
|
|
- TOC
|
|
{:toc}
|
|
---
|
|
|
|
## Prerequisites
|
|
ClusterFuzzLite supports statically linked
|
|
[libFuzzer targets]({{ site.baseurl }}/reference/glossary/#fuzz-target) on
|
|
Linux.
|
|
|
|
We re-use the [OSS-Fuzz](https://github.com/google/oss-fuzz) toolchain to make
|
|
building easier. If you are familiar with this, most of the concepts here are
|
|
exactly the same, with one key difference. Rather than checking out the source
|
|
code in the [`Dockerfile`](#dockerfile) using `git clone`, the `Dockerfile`
|
|
copies in the source code directly during `docker build`.
|
|
|
|
Before you can start setting up your new project for fuzzing, you must do the following:
|
|
- [Integrate]({{ site.baseurl }}/advanced-topics/ideal-integration/) one or more [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target)
|
|
with the project you want to fuzz. For examples, see TODO.
|
|
- [Install Docker](https://docs.docker.com/engine/installation)
|
|
[Why Docker?]({{ site.baseurl }}/faq/#why-do-you-use-docker)
|
|
|
|
If you want to run `docker` without `sudo`, you can
|
|
[create a docker group](https://docs.docker.com/engine/installation/linux/ubuntulinux/#/create-a-docker-group).
|
|
|
|
**Note:** Docker images can consume significant disk space. Run
|
|
[docker-cleanup](https://gist.github.com/mikea/d23a839cba68778d94e0302e8a2c200f)
|
|
periodically to garbage-collect unused images.
|
|
|
|
- Clone the OSS-Fuzz repo: `git clone https://github.com/google/oss-fuzz.git`
|
|
|
|
## Generating an empty build integration
|
|
|
|
Build integrations consist of three configuration files:
|
|
* [./clusterfuzzlite/project.yaml](#projectyaml) - provides metadata about the project.
|
|
* [./clusterfuzzlite/Dockerfile](#dockerfile) - defines the container environment with information
|
|
on dependencies needed to build the project and its [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target).
|
|
* [./clusterfuzzlite/build.sh](#buildsh) - defines the build script that executes inside the Docker container and
|
|
generates the project build.
|
|
|
|
These must live in the `.clusterfuzzlite` directory in the root of your
|
|
project's source code checkout.
|
|
|
|
You can generate empty versions of these files with the following command:
|
|
|
|
```bash
|
|
$ cd /path/to/oss-fuzz
|
|
$ export PATH_TO_PROJECT=<path_to_your_project>
|
|
$ python infra/helper.py generate $PATH_TO_PROJECT --external
|
|
```
|
|
|
|
Once the configuration files are generated, you should modify them to fit your
|
|
project.
|
|
|
|
## project.yaml {#projectyaml}
|
|
|
|
This configuration file stores project metadata. The following attributes are
|
|
supported:
|
|
|
|
- [language](#language)
|
|
|
|
### language
|
|
|
|
Programming language the project is written in. Values you can specify include:
|
|
|
|
* `c`
|
|
* `c++`
|
|
* [`go`]({{ site.baseurl }}//getting-started/new-project-guide/go-lang/)
|
|
* [`rust`]({{ site.baseurl }}//getting-started/new-project-guide/rust-lang/)
|
|
* [`python`]({{ site.baseurl }}//getting-started/new-project-guide/python-lang/)
|
|
* [`jvm` (Java, Kotlin, Scala and other JVM-based languages)]({{ site.baseurl }}//getting-started/new-project-guide/jvm-lang/)
|
|
|
|
## Dockerfile {#dockerfile}
|
|
|
|
This integration file defines the Docker image for your project.
|
|
Your [build.sh](#buildsh) script will be executed in inside the container you
|
|
define.
|
|
For most projects, the image is simple:
|
|
```docker
|
|
FROM gcr.io/oss-fuzz-base/base-builder # base image with clang toolchain
|
|
RUN apt-get update && apt-get install -y ... # install required packages to build your project
|
|
COPY . $SRC/<project_name> # checkout all sources needed to build your project
|
|
WORKDIR $SRC/<project_name> # current directory for the build script
|
|
COPY ./clusterfuzzlite/build.sh fuzzer.cc $SRC/ # copy build script into src dir
|
|
```
|
|
TODO: Provide examples.
|
|
|
|
## build.sh {#buildsh}
|
|
|
|
This file defines how to build binaries for [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target) in your project.
|
|
The script is executed within the image built from your [Dockerfile](#Dockerfile).
|
|
|
|
In general, this script should do the following:
|
|
|
|
- Build the project using your build system with OSS-Fuzz's compiler.
|
|
- Provide OSS-Fuzz's compiler flags (defined as [environment variables](#Requirements)) to the build system.
|
|
- Build your [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target)
|
|
and link your project's build with `$LIB_FUZZING_ENGINE` (libFuzzer).
|
|
|
|
Resulting binaries should be placed in `$OUT`.
|
|
|
|
Here's an example from Expat
|
|
([source](https://github.com/google/oss-fuzz/blob/master/projects/expat/build.sh)):
|
|
|
|
```bash
|
|
#!/bin/bash -eu
|
|
|
|
./buildconf.sh
|
|
# configure scripts usually use correct environment variables.
|
|
./configure
|
|
|
|
make clean
|
|
make -j$(nproc) all
|
|
|
|
$CXX $CXXFLAGS -std=c++11 -Ilib/ \
|
|
$SRC/parse_fuzzer.cc -o $OUT/parse_fuzzer \
|
|
$LIB_FUZZING_ENGINE .libs/libexpat.a
|
|
|
|
cp $SRC/*.dict $SRC/*.options $OUT/
|
|
```
|
|
|
|
If your project is written in Go, check out the [Integrating a Go project]({{ site.baseurl }}//getting-started/new-project-guide/go-lang/) page.
|
|
|
|
**Note:**
|
|
1. Make sure that the binary names for your [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target) contain only
|
|
alphanumeric characters, underscore(_) or dash(-). Otherwise, they won't run.
|
|
1. Don't remove source code files. They are needed for code coverage.
|
|
|
|
|
|
### Temporarily disabling code instrumentation during builds
|
|
|
|
In some cases, it's not necessary to instrument every 3rd party library or tool that supports the build target. Use the following snippet to build tools or libraries without instrumentation:
|
|
|
|
```
|
|
CFLAGS_SAVE="$CFLAGS"
|
|
CXXFLAGS_SAVE="$CXXFLAGS"
|
|
unset CFLAGS
|
|
unset CXXFLAGS
|
|
export AFL_NOOPT=1
|
|
|
|
#
|
|
# build commands here that should not result in instrumented code.
|
|
#
|
|
|
|
export CFLAGS="${CFLAGS_SAVE}"
|
|
export CXXFLAGS="${CXXFLAGS_SAVE}"
|
|
unset AFL_NOOPT
|
|
```
|
|
TODO: Figure out if we should include this AFL code.
|
|
|
|
### build.sh script environment
|
|
|
|
When your build.sh script is executed, the following locations are available within the image:
|
|
|
|
| Location| Env Variable | Description |
|
|
|---------| ------------ | ---------- |
|
|
| `/out/` | `$OUT` | Directory to store build artifacts (fuzz targets, dictionaries, options files, seed corpus archives). |
|
|
| `/src/` | `$SRC` | Directory to checkout source files. |
|
|
| `/work/`| `$WORK` | Directory to store intermediate files. |
|
|
|
|
Although the files layout is fixed within a container, environment variables are
|
|
provided so you can write retargetable scripts.
|
|
|
|
In case your fuzz target uses the [FuzzedDataProvider] class, make sure it is
|
|
included via `#include <fuzzer/FuzzedDataProvider.h>` directive.
|
|
|
|
[FuzzedDataProvider]: https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
|
|
|
|
### build.sh requirements {#Requirements}
|
|
|
|
Only binaries without an extension are accepted as targets. Extensions are reserved for other artifacts, like .dict.
|
|
|
|
You *must* use the special compiler flags needed to build your project and fuzz targets.
|
|
These flags are provided in the following environment variables:
|
|
|
|
| Env Variable | Description
|
|
| ------------- | --------
|
|
| `$CC`, `$CXX`, `$CCC` | The C and C++ compiler binaries.
|
|
| `$CFLAGS`, `$CXXFLAGS` | C and C++ compiler flags.
|
|
| `$LIB_FUZZING_ENGINE` | C++ compiler argument to link fuzz target against the prebuilt engine library (e.g. libFuzzer).
|
|
|
|
You *must* use `$CXX` as a linker, even if your project is written in pure C.
|
|
|
|
Most well-crafted build scripts will automatically use these variables. If not,
|
|
pass them manually to the build tool.
|
|
|
|
See the [Provided Environment Variables](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/README.md#provided-environment-variables) section in
|
|
`base-builder` image documentation for more details.
|
|
|
|
## Fuzzer execution environment
|
|
|
|
For more on the environment that
|
|
your [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target) run in, and the assumptions you can make, see the [fuzzer environment]({{ site.baseurl }}/further-reading/fuzzer-environment/) page.
|
|
|
|
## Testing locally
|
|
|
|
You can build your docker image and fuzz targets locally, so you can test them
|
|
before running ClusterFuzzLite.
|
|
1. Run the same helper script you used to create your directory structure, this time using it to build your docker image and [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target):
|
|
|
|
```bash
|
|
$ cd /path/to/oss-fuzz
|
|
$ python infra/helper.py build_image $PATH_TO_PROJECT --external
|
|
$ python infra/helper.py build_fuzzers $PATH_TO_PROJECT --sanitizer <address/undefined/coverage> --external
|
|
```
|
|
|
|
The built binaries appear in the `/path/to/oss-fuzz/build/out/$PROJECT_NAME`
|
|
directory on your machine (and `$OUT` in the container). Note that
|
|
`$PROJECT_NAME` is the name of the directory of your project (e.g. if
|
|
`$PATH_TO_PROJECT` is `/path/to/systemd`, `$PROJECT_NAME` is systemd.
|
|
|
|
**Note:** You *must* run your fuzz target binaries inside the base-runner docker
|
|
container to make sure that they work properly.
|
|
|
|
2. Find failures to fix by running the `check_build` command:
|
|
|
|
```bash
|
|
$ python infra/helper.py check_build $PATH_TO_PROJECT --external
|
|
```
|
|
|
|
3. If you want to test changes against a particular fuzz target, run the following command:
|
|
|
|
```bash
|
|
$ python infra/helper.py run_fuzzer --external --corpus-dir=<path-to-temp-corpus-dir> $PATH_TO_PROJECT <fuzz_target>
|
|
```
|
|
|
|
4. We recommend taking a look at your code coverage as a test to ensure that
|
|
your fuzz targets get to the code you expect. This would use the corpus
|
|
generated from the previous `run_fuzzer` step in your local corpus directory.
|
|
|
|
```bash
|
|
$ python infra/helper.py build_fuzzers --sanitizer coverage $PATH_TO_PROJECT
|
|
$ python infra/helper.py coverage $PATH_TO_PROJECT --fuzz-target=<fuzz_target> --corpus-dir=<path-to-temp-corpus-dir> --external
|
|
```
|
|
|
|
You may need to run `python infra/helper.py pull_images` to use the latest
|
|
coverage tools. Please refer to
|
|
[code coverage]({{ site.baseurl }}/advanced-topics/code-coverage/) for detailed
|
|
information on code coverage generation.
|
|
|
|
**Note:** Currently, ClusterFuzzLite only supports AddressSanitizer (address)
|
|
and UndefinedBehaviorSanitizer (undefined) configurations.
|
|
<b>Make sure to test each
|
|
of the supported build configurations with the above commands (build_fuzzers -> run_fuzzer -> coverage).</b>
|
|
|
|
If everything works locally, it should also work on ClusterFuzzLite. If you
|
|
check in your files and experience failures, review your [dependencies]({{site.baseurl }}/further-reading/fuzzer-environment/#dependencies).
|
|
|
|
## Debugging Problems
|
|
|
|
If you run into problems, the [Debugging page]({{ site.baseurl }}/advanced-topics/debugging/) lists ways to debug your build scripts and
|
|
[fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target).
|
|
|
|
## Efficient fuzzing
|
|
|
|
To improve your fuzz target ability to find bugs faster, please read [this section](
|
|
{{ site.baseurl }}/getting-started/new-project-guide/#efficient-fuzzing).
|
|
|
|
TODO(metzman): We probably want a TOC for lang-specific guides (which we still need to add).
|