2016-08-29 20:38:51 +00:00
|
|
|
# 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-09-01 18:39:23 +00:00
|
|
|
[Install Docker].
|
2016-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 19:27:58 +00:00
|
|
|
Building fuzzers requires building your library with a fresh of
|
|
|
|
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-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 19:27:58 +00:00
|
|
|
If you'd like to get more familiar with how building libFuzzer-style fuzzers work in
|
|
|
|
general, check out [this page](http://llvm.org/docs/LibFuzzer.html).
|
|
|
|
|
2016-09-27 19:17:38 +00:00
|
|
|
## Overview
|
2016-08-29 20:38:51 +00:00
|
|
|
|
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:
|
2016-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 21:07:19 +00:00
|
|
|
* *library_name*/Dockerfile - defines an container environment with all the dependencies needed to build the project and the fuzzer.
|
|
|
|
* *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-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 19:27:58 +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
|
2016-09-01 23:44:09 +00:00
|
|
|
$ export LIB_NAME=name_of_the_library
|
2016-09-12 19:55:23 +00:00
|
|
|
$ 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-08-29 20:38:51 +00:00
|
|
|
|
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:
|
|
|
|
```bash
|
|
|
|
FROM ossfuzz/base-libfuzzer # base image with clang toolchain
|
2016-09-29 20:02:03 +00:00
|
|
|
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
|
2016-09-27 20:41:52 +00:00
|
|
|
CMD /src/oss-fuzz/LIB_NAME/build.sh # specify build script for the project.
|
2016-08-29 20:38:51 +00:00
|
|
|
```
|
2016-09-27 20:41:52 +00:00
|
|
|
Expat example: [expat/Dockerfile](../expat/Dockerfile)
|
2016-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 19:17:38 +00:00
|
|
|
## build.sh
|
2016-08-29 20:38:51 +00:00
|
|
|
|
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`.
|
2016-08-29 20:38:51 +00:00
|
|
|
|
|
|
|
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).
|
2016-08-29 20:38:51 +00:00
|
|
|
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.
|
2016-08-29 20:38:51 +00:00
|
|
|
./configure
|
2016-09-27 20:41:52 +00:00
|
|
|
|
2016-08-29 20:38:51 +00:00
|
|
|
make clean all
|
|
|
|
|
|
|
|
# build the fuzzer, linking with libFuzzer and libexpat.a
|
|
|
|
$CXX $CXXFLAGS -std=c++11 -Ilib/ \
|
|
|
|
/src/oss-fuzz/expat/parse_fuzzer.cc -o /out/expat_parse_fuzzer \
|
2016-09-27 20:41:52 +00:00
|
|
|
/work/libfuzzer/*.o .libs/libexpat.a \
|
|
|
|
$LDFLAGS
|
2016-08-29 20:38:51 +00:00
|
|
|
```
|
|
|
|
|
2016-09-27 20:41:52 +00:00
|
|
|
### build.sh Script Environment
|
2016-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 20:41:52 +00:00
|
|
|
When build.sh script is executed, the following locations are available within the image:
|
2016-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 20:41:52 +00:00
|
|
|
| Path | Description
|
|
|
|
| ------ | -----
|
|
|
|
| `/src/$LIB_NAME` | Source code for your library.
|
|
|
|
| `/src/oss-fuzz` | Checked out oss-fuzz source tree.
|
|
|
|
| `/work/libfuzzer/*.o` | Prebuilt libFuzzer object files that need to be linked into all fuzzers.
|
|
|
|
|
|
|
|
You *must* use special compiler flags to build your library and fuzzers.
|
|
|
|
These flags are provided in following environment variables:
|
|
|
|
|
|
|
|
| Env Variable | Description
|
|
|
|
| ------------- | --------
|
|
|
|
| `$CC` | The C compiler binary.
|
|
|
|
| `$CXX`, `$CCC` | The C++ compiler binary.
|
|
|
|
| `$CFLAGS` | C compiler flags.
|
|
|
|
| `$CXXFLAGS` | C++ compiler flags.
|
|
|
|
| `$LDFLAGS` | Linker flags for fuzzer binaries.
|
|
|
|
|
|
|
|
Many well-crafted build scripts will automatically use these variables. If not,
|
|
|
|
passing them manually to a build tool might be required.
|
2016-08-29 20:38:51 +00:00
|
|
|
|
2016-09-27 21:07:19 +00:00
|
|
|
## 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;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
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-08-30 21:20:32 +00:00
|
|
|
### Dictionaries and custom libfuzzer options
|
|
|
|
|
|
|
|
Any top-level files in the library directory ending with the extension ".dict"
|
|
|
|
or ".options" will be picked up by ClusterFuzz. Files ending with ".dict" are
|
|
|
|
assumed to be libFuzzer compatible [dictionaries], and .options files have the
|
|
|
|
format:
|
|
|
|
|
|
|
|
```
|
|
|
|
[libfuzzer]
|
|
|
|
dict = dictionary_name.dict
|
|
|
|
max_len = 9001
|
|
|
|
```
|
|
|
|
|
|
|
|
This means that `-dict=/path/to/dictionary_name.dict` and `-max_len=9001` will
|
|
|
|
be passed to the fuzzer when it's run.
|
|
|
|
|
2016-08-29 20:38:51 +00:00
|
|
|
### Others (e.g. fuzzer source)
|
|
|
|
|
|
|
|
For some libraries, the upstream repository will contain fuzzers (e.g.
|
|
|
|
freetype2). In other cases, such as expat, we can check in fuzzer source into
|
|
|
|
the oss-fuzz repo.
|
|
|
|
|
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',
|
|
|
|
'https://github.com/google/oss-fuzz.git',
|
|
|
|
'master', null, '')
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2016-08-29 20:38:51 +00:00
|
|
|
## 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).
|
|
|
|
|
2016-08-29 20:38:51 +00:00
|
|
|
```bash
|
2016-09-27 20:41:52 +00:00
|
|
|
$ cd /path/to/oss-fuzz
|
2016-09-01 23:44:09 +00:00
|
|
|
$ python scripts/helper.py build_image $LIB_NAME
|
|
|
|
$ python scripts/helper.py build_fuzzers $LIB_NAME
|
2016-08-29 20:38:51 +00:00
|
|
|
```
|
|
|
|
|
2016-09-01 23:44:09 +00:00
|
|
|
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:
|
2016-08-29 20:38:51 +00:00
|
|
|
|
|
|
|
```bash
|
2016-09-01 23:44:09 +00:00
|
|
|
$ python scripts/helper.py run_fuzzer $LIB_NAME name_of_a_fuzzer
|
2016-08-29 20:38:51 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
If everything works locally, then it should also work on our automated builders
|
|
|
|
and ClusterFuzz.
|
|
|
|
|
2016-09-29 20:02:03 +00:00
|
|
|
### Debugging build scripts
|
|
|
|
|
|
|
|
While developing your build script, it may be useful to run bash within the
|
|
|
|
container:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ python scripts/helper.py shell $LIB_NAME # runs /bin/bash within container
|
|
|
|
$ bash /src/oss-fuzz/$LIB_NAME/build.sh # to run the build script manually
|
|
|
|
```
|
|
|
|
|
2016-08-29 20:38:51 +00:00
|
|
|
## Checking in to oss-fuzz repository
|
|
|
|
|
|
|
|
Fork oss-fuzz, commit and push to the fork, and then create a pull request with
|
|
|
|
your change!
|
|
|
|
|
|
|
|
### 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
|
2016-08-30 21:20:32 +00:00
|
|
|
[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/
|