oss-fuzz/docs/new_library.md

264 lines
9.0 KiB
Markdown
Raw Normal View History

# Setting up fuzzers for a new library
Fuzzer build configurations are placed into a top-level directory for the
library in the [oss-fuzz repo] on GitHub. For example, fuzzers for the expat
library go into <https://github.com/google/oss-fuzz/tree/master/expat>.
## Prerequisites
2016-10-12 20:23:00 +00:00
[Install Docker]. (Googlers: [go/installdocker](https://goto.google.com/installdocker) )
2016-10-13 15:09:12 +00:00
*NOTE: if you want to run `docker` without `sudo` also follow the optional [Create a docker group](https://docs.docker.com/engine/installation/linux/ubuntulinux/#/create-a-docker-group) section.*
2016-10-12 01:26:42 +00:00
*NOTE: Docker images can consume significant disk space. Run*
2016-10-12 01:27:02 +00:00
*[docker-cleanup](https://gist.github.com/mikea/d23a839cba68778d94e0302e8a2c200f)*
2016-10-12 01:26:42 +00:00
*periodically to garbage collect unused images.*
2016-10-12 12:22:24 +00:00
Building fuzzers requires building your library with a fresh
2016-09-27 19:27:58 +00:00
Clang compiler and special compiler flags. An easy-to-use Docker image is
2016-09-27 18:33:54 +00:00
provided to simplify tool distribution.
2016-10-12 12:22:24 +00:00
If you'd like to get more familiar with how libFuzzer-style fuzzers work in
2016-09-27 19:27:58 +00:00
general, check out [this page](http://llvm.org/docs/LibFuzzer.html).
2016-09-27 19:17:38 +00:00
## Overview
2016-09-27 21:07:19 +00:00
To add a new OSS library to oss-fuzz, 3 supporting files have to be added to oss-fuzz source code repository:
* `library_name/Dockerfile` - defines an container environment with all the dependencies
needed to build the project and the fuzzer.
2016-10-10 16:59:53 +00:00
* `library_name/build.sh` - build script that will be executed inside the container.
* `library_name/Jenkinsfile` - will be needed to integrate fuzzers with ClusterFuzz build and distributed execution system.
2016-09-27 20:56:30 +00:00
Specify your library VCS location in it.
2016-10-10 16:59:53 +00:00
To create a new directory for the library and *automatically generate* these 3 files a python script can be used:
2016-09-01 18:43:44 +00:00
```bash
2016-09-27 18:39:04 +00:00
$ cd /path/to/oss-fuzz
$ export LIB_NAME=name_of_the_library
$ python scripts/helper.py generate $LIB_NAME
2016-09-01 18:43:44 +00:00
```
2016-09-27 21:07:19 +00:00
Create a fuzzer and add it to the *library_name/* directory as well.
2016-09-27 19:17:38 +00:00
## Dockerfile
2016-09-27 20:41:52 +00:00
This is the Docker image definition that build.sh will be executed in.
2016-09-27 19:27:58 +00:00
It is very simple for most libraries:
```docker
2016-09-27 19:27:58 +00:00
FROM ossfuzz/base-libfuzzer # base image with clang toolchain
MAINTAINER YOUR_EMAIL # each file should have a maintainer
2016-09-27 19:27:58 +00:00
RUN apt-get install -y ... # install required packages to build a project
RUN git checkout <git_url> # checkout all sources needed to build your library
2016-10-19 20:04:35 +00:00
COPY build.sh fuzzer.cc /src/ # install build script and other source files.
```
2016-09-27 20:41:52 +00:00
Expat example: [expat/Dockerfile](../expat/Dockerfile)
## Create Fuzzer Source File
Create a new .cc file, define a `LLVMFuzzerTestOneInput` function and call
your library:
```c++
#include <stddef.h>
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// put your fuzzing code here and use data+size as input.
return 0;
}
```
Make sure you add the file to your Docker image:
```docker
COPY build.sh my_fuzzer.cc /src/ # install build script & fuzzer.
```
There are [lots](../libxml2/libxml2_xml_read_memory_fuzzer.cc)
[of](../expat/parse_fuzzer.cc) [examples](../zlib/zlib_uncompress_fuzzer.cc)
in this project repository.
2016-09-27 19:17:38 +00:00
## build.sh
2016-09-27 20:41:52 +00:00
This is where most of the work is done to build fuzzers for your library. The script will
be executed within an image built from a `Dockerfile`.
In general, this script will need to:
2016-09-27 20:53:38 +00:00
1. Build the library using its build system *with* correct compiler and its flags provided as *environment variables* (see below).
2. Build the fuzzers, linking with the library and libFuzzer. Built fuzzers
should be placed in `/out`.
For expat, this looks like:
```bash
#!/bin/bash -eu
cd /src/expat/expat
./buildconf.sh
2016-09-27 20:41:52 +00:00
# configure scripts usually use correct environment variables.
./configure
2016-09-27 20:41:52 +00:00
make clean all
# build the fuzzer, linking with libFuzzer and libexpat.a
$CXX $CXXFLAGS -std=c++11 -Ilib/ \
2016-10-19 20:04:35 +00:00
/src/parse_fuzzer.cc -o /out/expat_parse_fuzzer \
-lfuzzer .libs/libexpat.a \
$FUZZER_LDFLAGS
```
2016-09-27 20:41:52 +00:00
### build.sh Script Environment
2016-09-27 20:41:52 +00:00
When build.sh script is executed, the following locations are available within the image:
| Path | Description
| ------ | -----
| `/src/<some_dir>` | Source code needed to build your library.
| `/usr/lib/libfuzzer.a` | Prebuilt libFuzzer library that need to be linked into all fuzzers (`-lfuzzer`).
2016-09-27 20:41:52 +00:00
You *must* use special compiler flags to build your library and fuzzers.
These flags are provided in following environment variables:
| Env Variable | Description
| ------------- | --------
| `$CC`, `$CXX`, `$CCC` | The C and C++ compiler binaries.
| `$CFLAGS`, `$CXXFLAGS` | C and C++ compiler flags.
| `$FUZZER_LDFLAGS` | Linker flags for fuzzer binaries.
2016-09-27 20:41:52 +00:00
Many well-crafted build scripts will automatically use these variables. If not,
passing them manually to a build tool might be required.
2016-10-13 21:03:43 +00:00
See [Provided Environment Variables](../infra/base-images/base-libfuzzer/README.md#provided-environment-variables) section in
`base-libfuzzer` image documentation for more details.
2016-10-13 15:24:56 +00:00
### Custom libFuzzer options for ClusterFuzz
2016-09-27 21:07:19 +00:00
2016-10-13 15:27:26 +00:00
By default ClusterFuzz will run your fuzzer without any options. You can specify
custom options by creating a `fuzzer_name.options` file next to a fuzzier in `/out`:
```
2016-10-13 15:33:02 +00:00
[libfuzzer]
2016-10-13 15:24:56 +00:00
max_len = 1024
```
2016-10-13 15:27:26 +00:00
[List of available options](http://llvm.org/docs/LibFuzzer.html#options)
2016-10-13 15:24:56 +00:00
2016-10-13 15:27:26 +00:00
At least `max_len` is highly recommended.
For out of tree fuzzers you will likely add options file using docker's
2016-10-13 15:24:56 +00:00
`COPY` directive and will copy it into output in build script.
### Dictionaries
2016-10-13 15:24:56 +00:00
Dictionaries hugely improve fuzzer effectiveness for inputs with lots of similar
sequences of bytes. [libFuzzer documentation](http://llvm.org/docs/LibFuzzer.html#dictionaries)
2016-10-13 15:24:56 +00:00
Put your dict files in `/out` and specify them in .options file:
```
[libfuzzer]
dict = dictionary_name.dict
```
2016-10-17 19:39:28 +00:00
### Seed corpora
You can also pass a set of initial seed files to your fuzzers. This is typically
a set of valid inputs to the target function you are testing, and can improve
coverage significantly.
This can be done by zipping up these files, naming them
`fuzzer_name_seed_corpus.zip`, and placing them in `/out` in your build script.
2016-09-27 20:56:30 +00:00
## Jenkinsfile
This file will be largely the same for most libraries, and is used by our build
infrastructure. For expat, this is:
```groovy
// load libFuzzer pipeline definition.
def libfuzzerBuild = fileLoader.fromGit('infra/libfuzzer-pipeline.groovy',
2016-10-11 21:39:47 +00:00
'https://github.com/google/oss-fuzz.git')
2016-09-27 20:56:30 +00:00
libfuzzerBuild {
git = "git://git.code.sf.net/p/expat/code_git"
}
```
Simply replace the the "git" entry with the correct git url for the library.
*Note*: only git is supported right now.
## Testing locally
2016-09-27 20:41:52 +00:00
Helper script can be used to build images and fuzzers. Non-script
version using docker commands directly is documented [here](building_running_fuzzers_external.md).
```bash
2016-09-27 20:41:52 +00:00
$ cd /path/to/oss-fuzz
$ python scripts/helper.py build_image $LIB_NAME
$ python scripts/helper.py build_fuzzers $LIB_NAME
```
This should place the built fuzzers into `/path/to/oss-fuzz/build/out/$LIB_NAME`
on your machine (`/out` in the container). You can then try to run these fuzzers
inside the container to make sure that they work properly:
```bash
2016-10-13 15:09:12 +00:00
$ python scripts/helper.py run_fuzzer $LIB_NAME name_of_a_fuzzer
```
If everything works locally, then it should also work on our automated builders
and ClusterFuzz.
2016-10-14 01:07:57 +00:00
It's recommended to look at coverage as a sanity check to make sure that fuzzer gets to the code you expect.
```bash
2016-10-19 18:17:27 +00:00
$ python scripts/helper.py coverage $LIB_NAME name_of_a_fuzzer
2016-10-14 01:07:57 +00:00
```
2016-10-04 18:55:46 +00:00
## Debugging Problems
2016-10-04 18:58:18 +00:00
[Debugging](debugging.md) document lists ways to debug your build scripts or fuzzers
in case you run into problems.
## Checking in to oss-fuzz repository
Fork oss-fuzz, commit and push to the fork, and then create a pull request with
2016-10-13 21:07:40 +00:00
your change! Follow the [Forking Project](https://guides.github.com/activities/forking/) guide
if you are new to contributing via GitHub.
### Copyright headers
Please include copyright headers for all files checked in to oss-fuzz:
```
# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
```
If porting a fuzzer from Chromium, keep the Chromium license header.
## The end
Once your change is merged, the fuzzers should be automatically built and run on
ClusterFuzz after a short while!
[oss-fuzz repo]: https://github.com/google/oss-fuzz
[dictionaries]: http://llvm.org/docs/LibFuzzer.html#dictionaries
2016-09-01 18:39:23 +00:00
[Install Docker]: https://docs.docker.com/engine/installation/linux/ubuntulinux/