aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs/ideal_integration.md
blob: 80554b70e21b232d7da0b0203361e600c3582351 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Ideal integration with OSS-Fuzz 
OSS projects have different build and test systems. So, we can not expect them
to have a unified way of implementing and maintaining fuzz targets and integrating
them with OSS-Fuzz. However, we will still try to give recommendations on the preferred ways.

Here are several features (starting from the easiest) that will make automated fuzzing
simple and efficient, and will allow to catch regressions early on in the development cycle. 

## Fuzz Target
The code of the [fuzz target(s)](http://libfuzzer.info/#fuzz-target) should be part of the project's source code repository. 
All fuzz targets should be easily discoverable (e.g. reside in the same directory, or follow the same naming pattern, etc). 

This makes it easy to maintain the fuzzers and minimizes breakages that can arise as source code changes over time.

Make sure to fuzz the target locally for a small period of time to ensure that 
it does not crash, hang, or runs out of memory instantly. 
See details at http://libfuzzer.info and http://tutorial.libfuzzer.info

Examples: 
[boringssl](https://github.com/google/boringssl/tree/master/fuzz),
[SQLite](https://www.sqlite.org/src/artifact/ad79e867fb504338),
[s2n](https://github.com/awslabs/s2n/tree/master/tests/fuzz),
[openssl](https://github.com/openssl/openssl/tree/master/fuzz),
[FreeType](http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/tools/ftfuzzer),
[re2](https://github.com/google/re2/tree/master/re2/fuzzing),
[harfbuzz](https://github.com/behdad/harfbuzz/tree/master/test/fuzzing),
[pcre2](http://vcs.pcre.org/pcre2/code/trunk/src/pcre2_fuzzsupport.c?view=markup),
[ffmpeg](https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/decoder_targeted.c).


## Seed Corpus
The *corpus* is a set of inputs for the fuzz target (stored as individual files). 
When starting the fuzzing process, one should have a "seed corpus", 
i.e. a set of inputs to "seed" the mutations.
The quality of the seed corpus has a huge impact on the fuzzing efficiency as it allows the fuzzer
to discover new code paths easier. 

The ideal corpus is a minimial set of intputs that provides maximal code coverage. 

For better OSS-Fuzz integration 
the seed corpus should be available in revision control (can be same or different as the source code). 
It should be regularly extended with the inputs that (used to) trigger bugs and/or touch new parts of the code. 

Examples: 
[boringssl](https://github.com/google/boringssl/tree/master/fuzz),
[openssl](https://github.com/openssl/openssl/tree/master/fuzz),
[nss](https://github.com/mozilla/nss-fuzzing-corpus) (corpus in a separate repo) 


## Regression Testing
The fuzz targets should be regularly tested (not necessary fuzzed!) as a part of the project's regression testing process.
One way to do so is to link the fuzz target with a simple driver
(e.g. [this one](https://github.com/llvm-mirror/llvm/tree/master/lib/Fuzzer/standalone))
that runs the provided inputs and use this driver with the seed corpus created in previous step. 
It is recommended to use the [sanitizers](https://github.com/google/sanitizers) during regression testing.

Examples: [SQLite](https://www.sqlite.org/src/artifact/d9f1a6f43e7bab45),
[openssl](https://github.com/openssl/openssl/blob/master/fuzz/test-corpus.c)

## Fuzzing dictionary

For some input types a simple dictionary of tokens used by the input language
may have dramatic positive effect on fuzzing. 
For example, when fuzzing an XML parser, a dictionary of XML tokens will help.
AFL has a [collection](https://github.com/rc0r/afl-fuzz/tree/master/dictionaries)
of such dictionaries for some of the popular data formats.
Ideally, a dictionary should be maintained alongside the fuzz target.
The syntax is described [here](http://libfuzzer.info/#dictionaries).

## Build support
A plethora of different build systems exist in the open-source world.
And the less OSS-Fuzz knows about them, the better it can scale. 

An ideal build integration for OSS-Fuzz would look like this:
* For every fuzz target `foo` in the project, there is a build rule that builds `foo_fuzzer.a`,
an archive that contains the fuzzing entry point (`LLVMFuzzerTestOneInput`)
and all the code it depends on, but not the `main()` function
* The build system supports changing the compiler and passing extra compiler
flags so that the build command for a `foo_fuzzer.a` looks similar to this:

```
CC="clang $FUZZER_FLAGS" CXX="clang++ $FUZZER_FLAGS" make_or_whatever_other_command foo_fuzzer.a
```

In this case, linking the target with e.g. libFuzzer will look like "clang++ foo_fuzzer.a libFuzzer.a".
This will allow to have minimal OSS-Fuzz-specific configuration and thus be more robust. 

There is no point in hardcoding the exact compiler flags in the build system because they 
a) may change and b) are different depending on the fuzzing target and the sanitizer being used. 

## Not a project member?

If you are a member of the project you want to fuzz, most of the steps above are simple.
However in some cases someone outside the project team may want to fuzz the code
and the project maintainers are not interested in helping.

In such cases we can host the fuzz targets, dictionaries, etc in this
repository and mention them in the Dockerfile.
Examples: [libxml2](../targets/libxml2), [c-ares](../targets/c-ares), [expat](../targets/expat).
This is far from ideal because the fuzz targets will not be continuosly tested 
and hence may quickly bitrot.

If you are not a project maintainer we may not be able to CC you to security bugs found by OSS-Fuzz.