ClusterFuzzLite is a continuous fuzzing solution that runs as part of Continuous Integration (CI) workflows to find vulnerabilities faster than ever before. With just a few lines of code, GitHub users can integrate ClusterFuzzLite into their workflow and fuzz pull requests to catch bugs before they are committed.

ClusterFuzzLite is based on ClusterFuzz.

Features

  • Quick code change (pull request) fuzzing to find bugs before they land
  • Downloads of crashing testcases
  • Continuous longer running fuzzing (batch fuzzing) to asynchronously find deeper bugs missed during code change fuzzing and build a corpus for use in code change fuzzing
  • Coverage reports showing which parts of your code are fuzzed
  • Modular functionality, so you can decide which features you want to use

Supported Languages

  • C
  • C++
  • Java (and other JVM-based languages)
  • Go
  • Python
  • Rust
  • Swift

Supported CI Systems

  • GitHub Actions
  • Google Cloud Build
  • Prow
  • Support for more CI systems is in-progess, and extending support to other CI systems is easy

Supported Fuzzing Engine and Sanitizers

  • libFuzzer for coverage-guided testing
  • AddressSanitizer for finding memory safety issues
  • MemorySanitizer for finding use of uninitialized memory
  • UndefinedBehaviorSanitizer for finding undefined behavior (e.g. integer overflows)

Introducing fuzzing with libFuzzer and Sanitizers.

This section provides an overview of the fuzzing process and defines common terms. If you are already familiar with libFuzzer and Sanitizers, feel free to skip to Step 1: Build Integration to begin writing fuzzers and integrating with ClusterFuzzLite’s build system.

Fuzzing

Fuzzing is a technique where randomized inputs are automatically created and fed as input to a (target) program in order to find bugs in that program. The program that creates the inputs is called a fuzzer. Fuzzing is highly effective at finding bugs missed by manually written tests, code review, or auditing. Fuzzing has found thousands of bugs in mature software such as Chrome, OpenSSL, and Curl. When done well, fuzzing is able to find bugs in virtually any code.

libFuzzer

LibFuzzer is a fuzzer (sometimes called a fuzzing engine) that mutates inputs and feeds them to target code in a loop. During execution of the target on the input, libFuzzer observes the coverage of the code under test using instrumentation inserted by the compiler. LibFuzzer uses this coverage feedback to “evolve” progressively more interesting inputs and reach deeper program states, allowing it to find interesting bugs with little developer effort.

Fuzz target

To fuzz target code, you must define a function called a fuzz target with the following API:

fuzz_target.cc
extern “C” int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DoSomethingInterestingWithMyAPI(Data, Size);
return 0; // Non-zero return values are reserved for future use.
}

Clang’s -fsanitizer=fuzzer option will link this fuzz target function against libFuzzer, producing a fuzzer binary that will fuzz your target code when run. Note that in ClusterFuzzLite, you will not use this flag directly. Instead, you should use the $LIB_FUZZING_ENGINE environment variable, which is discussed in more detail in Step 1: Build Integration.

Sanitizers

Sanitizers are tools that detect bugs in code (typically “native code” such as C/C++, Rust, Go, and Swift) and report bugs by crashing. ClusterFuzzLite relies on sanitizers to detect bugs that would otherwise be missed. Sanitizers work by instructing clang to add compile-time instrumentation, so different builds are needed to use different sanitizers.

The sanitizers ClusterFuzzLite uses are:

  • AddressSanitizer (ASan) : For detecting memory safety issues. This is the most important sanitizer to fuzz with. AddressSanitizer also detects memory leaks.
  • UndefinedBehaviorSanitizer (UBSan) : For detecting undefined behavior such as integer overflows.
  • MemorySanitizer (MSan) : For detecting use of uninitialized memory. MSan is the hardest sanitizer to use because an MSan instrumented binary must be entirely instrumented with MSan. If any part of the binary is not instrumented with MSan, MSan will report false positives.

The ClusterFuzzLite codebase uses shorter names for the sanitizers. When referring to a sanitizer as an input to ClusterFuzzLite, ASan is address, UBSan is ubsan and MSan is memory.

Build Integration

This page explains how to integrate your project with ClusterFuzzLite’s build system so that ClusterFuzzLite can build your project’s fuzz targets with sanitizers. ClusterFuzzLite is intimately tied to sanitizers and libFuzzer. By integrating with our build system, ClusterFuzzLite will be able to use the most recent versions of these tools to secure your code.

By the end of the document you will be able to build and run your fuzz targets with libFuzzer and a variety of sanitizers.

Prerequisites

ClusterFuzzLite supports libFuzzer targets built with Clang on Linux.

ClusterFuzzLite reuses the OSS-Fuzz toolchain to make building easier. This means that ClusterFuzzLite will build your project in a docker container. If you are familiar with OSS-Fuzz, most of the concepts here are exactly the same, with one key difference. Rather than checking out the source code in the Dockerfile using git clone, the Dockerfile copies in the source code directly during docker build. Another minor difference is that ClusterFuzzLite only supports libFuzzer and not other fuzzing engines. If you are not familiar with OSS-Fuzz, have no fear! This document is written with you in mind and assumes no knowledge of OSS-Fuzz.

Before you can start setting up your new project for fuzzing, you must do the following to use the ClusterFuzzLite toolchain:

  • Integrate fuzz targets with your codebase. See this page for more details.
  • Install DockerIf you want to run docker without sudo, you can create a docker group. Note: Docker images can consume significant disk space. Run docker-cleanup 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

Next you need to configure your project to build fuzzers on ClusterFuzzLite. To do this, your project needs three configuration files in the .clusterfuzzlite directory in your project’s root:

  • .clusterfuzzlite/project.yaml – provides metadata about the project.
  • .clusterfuzzlite/Dockerfile – defines the container environment with information on dependencies needed to build the project and its fuzz targets.
  • .clusterfuzzlite/build.sh – defines the build script that executes inside the Docker container and builds your project and its fuzz targets.

You can generate empty versions of these files with the following command:

cd /path/to/oss-fuzz
export PATH_TO_PROJECT=
python infra/helper.py generate –external –language=c++ $PATH_TO_PROJECT

Note that you may need to change the --language argument to another value if your project is written in another language. This is discussed more in the language section.

Once the configuration files are generated, you should modify them to fit your project. Let’s look at each file one-by-one and explain what you should add to them.

project.yaml

This configuration file stores project metadata. Currently it is only used by helper.py to build your project. The only field you must fill out in this file is:

language

Programming language the project is written in. Values you can specify include:

  • c
  • c++
  • go
  • rust
  • python
  • jvm
    • This should be used for Java, Kotlin, Scala and other JVM-based languages.
  • swift

Most of this guide applies directly to C/C++ projects. Please see the relevant subguides for how to build fuzzers for that language. Note that c and c++ are the same to ClusterFuzzLite.

Dockerfile

This integration file defines the Docker image for building your project. Your build.sh script will be executed inside the image this file defines. For most projects, the Dockerfile is simple:

FROM gcr.io/oss-fuzz-base/base-builder:v1 # Base image with clang toolchain
RUN apt-get update && apt-get install -y … # Install required packages to build your project.
COPY . $SRC/ # Copy your project’s source code.
WORKDIR $SRC/ # Working directory for build.sh.
COPY ./.clusterfuzzlite/build.sh $SRC/ # Copy build.sh into
$SRC dir.

build.sh

This script must build binaries for fuzz targets in your project. The script is executed within the image built from your Dockerfile.

In general, this script should do the following:

  • Build the project using your build system with ClusterFuzzLite’s compiler.
  • Provide ClusterFuzzLite’s compiler flags (defined as environment variables) to the build system.
  • Build your fuzz targets and link them with the $LIB_FUZZING_ENGINE (libFuzzer) environment variable.
  • Place any fuzz target binaries in the directory defined by the environment variable $OUT.

Make sure that the binary names for your fuzz targets contain only alphanumeric characters, underscore (_) or dash (-). They should not contain periods (.) or have file extensions. Otherwise, they won’t run. Your build.sh should not delete any source code. Source code is needed for code coverage reports.

The $WORK environment variable defines a directory where build.sh can store intermediate files.

Here’s an example build.sh from Expat:

build.sh environment variables for compilation

You must use ClusterFuzzLite’s compilers and compiler flags to build your fuzz targets. These are provided in the following environment variables:

Env VariableDescription
$CC$CXX$CCCC and C++ compilers.
$CFLAGS$CXXFLAGSC and C++ compiler flags.
$LIB_FUZZING_ENGINEC++ compiler argument to link fuzz target against libFuzzer.

These compiler flags are needed to properly instrument your fuzzers with sanitizers and coverage instrumentation.

Note that even if your project is written in pure C you must use $CXX to link your fuzz target binaries.

Many build tools will automatically use these environment variables (with the exception of $LIB_FUZZING_ENGINE). If not, pass them manually to the build tool.

You can also do the final linking step with $LIB_FUZZING_ENGINE in your build.sh.

See the Provided Environment Variables page in OSS-Fuzz’s base-builder image documentation for more details on environment variables that are available to build.sh.

Fuzzer execution environment

You should not make any assumptions on the availability of dependent packages in the execution environment and the built fuzzers should have dependencies statically linked.

Testing locally

When you have completed writing the build.sh and Dockerfile, you should test that they work. This includes running your fuzz targets, which we strongly recommend. The helper.py script you used to generate your config files offers a few different ways of doing this:

  1. Build your docker image and fuzz targets:

python infra/helper.py build_image –external $PATH_TO_PROJECT
python infra/helper.py build_fuzzers –external $PATH_TO_PROJECT –sanitizer

  1. The built binaries appear in the /path/to/oss-fuzz/build/out/$PROJECT_NAME directory on your host machine (and $OUT in the container). Note that $PROJECT_NAME is the name of the root directory of your project (e.g. if $PATH_TO_PROJECT is /path/to/systemd$PROJECT_NAME is systemd).
  2. Find common build issues to fix by running the check_build command:

python infra/helper.py check_build –external $PATH_TO_PROJECT –sanitizer

  1. This checks that your fuzz targets are compiled with the right sanitizer and don’t crash after fuzzing for a few seconds.
  2. To run a particular fuzz target, use run_fuzzer:

python infra/helper.py run_fuzzer –external –corpus-dir= $PATH_TO_PROJECT

If you are going to use the code coverage report feature of ClusterFuzzLite it is a good idea to test that coverage report generation works. This would use the corpus generated from the previous run_fuzzer step in your local corpus directory.

python infra/helper.py build_fuzzers –external –sanitizer coverage $PATH_TO_PROJECT
python infra/helper.py coverage –external $PATH_TO_PROJECT –fuzz-target= –corpus-dir=

You may need to run python infra/helper.py pull_images to use the latest coverage tools.

Make sure to test each of the sanitizers with build_fuzzerscheck_build, and run_fuzzer.

If everything works locally, it should also work on ClusterFuzzLite. If you experience failures running fuzzers on ClusterFuzzLite, review your dependencies.

Debugging Problems

If you run into problems, the Debugging page lists ways to debug your build scripts and fuzz targets.

Efficient fuzzing

To improve your fuzz target ability to find bugs faster, please read this section.

Running ClusterFuzzLite

Next: Step 2: Running ClusterFuzzLite for directions on setting up ClusterFuzzLite to run on your CI.

Running ClusterFuzzLite

Before running ClusterFuzzLite, you must integrate your project with ClusterFuzzLite’s build system to build your project’s fuzzers. See Step 1: Build Integration if you haven’t already taken this step.

Overview

The exact method for running ClusterFuzzLite will depend on which CI system you are using. The rest of this page explains important concepts and configuration options that are agnostic to which CI system you are using. After reading this page, see the subguides for instructions specific to your particular CI system (e.g. GitHub Actions or Google Cloud Build).

ClusterFuzzLite Modes

ClusterFuzzLite offers two primary modes of fuzzing: code change fuzzing and batch fuzzing. ClusterFuzzLite also offers two helper modes for running fuzzers that don’t actually fuzz but provide useful functionality: prune and coverage. ClusterFuzzLite can be instructed to perform any of these functions using the “mode” option.

Code Change Fuzzing (“code-change”)

The core way to use ClusterFuzzLite is to fuzz code changes that were introduced in a pull request/code review or commit. Code change fuzzing allows ClusterFuzzLite to find bugs before they are commited into your code and while they are easiest to fix.

Code change fuzzing is designed to be fast so that it integrates easily into your development workcycle:

  • It defaults to fuzzing for 10 minutes, though this can be changed.
  • It quits after finding a single crash, even if there are other fuzzers to run.

Running only code change fuzzing is the easiest way to use ClusterFuzzLite. However, we suggest using code change fuzzing in conjunction with other modes to gain ClusterFuzzLite’s full benefits.

For example, running batch fuzzing will develop a corpus that can be used by code change fuzzing. (If no corpus is available from batch fuzzing, code change fuzzing will start from nothing or the provided seed corpus.) Furthermore, when you first use ClusterFuzzLite, code change fuzzing will not report the bugs that already exist in your codebase, while batch fuzzing will. See also Code Coverage Report Generation and Continuous Builds for additional functionalities.

Batch Fuzzing (“batch”)

In batch fuzzing mode all fuzzers are run for a preset, longer, amount of time. Unlike in code change mode, batch fuzzing will not exit immediately upon discovering a bug. It will keep running other fuzzers until reaching the allotted fuzzing time.

Given the longer runtime, we suggest batch fuzzing should be run on a schedule such as once daily, rather than on code changes.

By running for a longer amount of time, batch fuzzing serves two important purposes:

  • It can find bugs that are missed or are not reported by code change fuzzing. Note that batch fuzzing reports all crashes, not just “new” ones.
  • It builds a corpus for each of your fuzz targets, leading to more code coverage and better bug discovery. This corpus will be used by Code coverage report generation, code change fuzzing, and later runs of batch fuzzing. The corpus is saved using your CI system’s feature for storing files.

Corpus Pruning (“prune”)

Over time, redundant testcases will get introduced into your fuzzer’s corpuses during batch fuzzing.

Corpus pruning is a helper function that minimizes the corpuses by removing corpus files (testcases) that do not increase the fuzzer’s code coverage.

If you are using batch fuzzing, you should run corpus pruning once a day to prevent buildup of these redundant testcases and keep fuzzing efficient. Corpus pruning should be considered mandatory when you are using batch fuzzing but otherwise should not be used.

Code Coverage Report Generation (“coverage”)

Code coverage report generation is a helper function that can be used when batch fuzzing is enabled. This mode uses the corpus developed during batch fuzzing to generate an HTML coverage report that shows which parts of your code are covered by fuzzing.

The data from coverage reports is also used by code change fuzzing to determine which fuzzers are affected by a code change. If code change fuzzing can determine which fuzzers are affected, it will run only those fuzzers. Otherwise, it will run all of them. Coverage report generation uses the corpuses saved by batch fuzzing and therefore should only be used if batch fuzzing is enabled. It is not required if batch fuzzing is enabled, but is strongly recommended.

Continuous Builds

Continuous builds are not actually a mode of running fuzzers but is an additional “task” for ClusterFuzzLite that you can set up. Instead of running the fuzzers after building them, the continuous builds task saves the builds for later use by the code change fuzzing mode.

The continuous builds task enables code change fuzzing to identify whether the cause of a crash was introduced by the code change. With the continuous builds task, if the cause of the crash was pre-existing, the crash is not reported by code change fuzzing. If code change fuzzing is run without the continuous builds task, all crashes will be reported.

Configuration Options

This section is an overview of the configuration options you can set when running ClusterFuzzLite. See the subguides for details on how to set each configuration within your specific CI system.

  • language: The language your target code is written in. Defaults to c++. This should be the same as the value you set in project.yaml. See this explanation for more details.
  • fuzz-seconds: Instructs ClusterFuzzLite on how long to spend fuzzing, in seconds. The default is 600 seconds, which is an appropriate starting point for code change fuzzing. You should increase this number to spend more time batch fuzzing.
  • sanitizer: Determines the sanitizer to build and run fuzz targets with. The choices are 'address''undefined''memory' and 'coverage' (for coverage report generation). The default is 'address'. See Sanitizers for more information.
  • mode: The mode for ClusterFuzzLite to execute. code-change by default. See ClusterFuzzLite modes for more details on how to run different modes.
  • dry-run: Determines if ClusterFuzzLite reports bugs/crashes. The default value is false. When set to true, ClusterFuzzLite will never report a failure even if it finds a crash in your project, and users will have to manually check the logs for detected bugs. This should only be used for testing ClusterFuzzLite.

Note: Your specific CI system will determine how options are passed to ClusterFuzzLite. Because some CI systems will pass them using environment variables, the names of the environment variables can be slightly different than names of the corresponding options. In particular, environment variables will be all uppercase and use underscores (_) instead of hyphens (-). For example: the environment variable for fuzz-seconds is FUZZ_SECONDS.

At this point you are ready to run ClusterFuzzLite using your specific CI system!

Next: choose the subguide for your CI system.

Supported Continous Integration Systems

GitHub Actions

This page explains how to set up ClusterFuzzLite to run on GitHub Actions. To get the most of this page, you should have already set up your build integration and read the more high-level document on running ClusterFuzzLite.

Workflow Files

For basic ClusterFuzzLite functionality, all you need is a single workflow file to enable fuzzing on your pull requests.

  • .github/workflows/cflite_pr.yml (for PR fuzzing)

To enable more features, we recommend having these additional files:

  • .github/workflows/cflite_build.yml (for continuous builds)
  • .github/workflows/cflite_batch.yml (for batch fuzzing)
  • .github/workflows/cflite_cron.yml (for tasks done on a cron schedule: pruning and coverage)

These workflow files are used by GitHub actions to run the ClusterFuzzLite actions. For a complete example on a real project, see https://github.com/oliverchang/curl.

Mode Configurations

The following configuration guides show default configuration settings for each workflow file. Simply copying the default settings should work for most projects, or you can choose to edit the files to customize the settings.

PR fuzzing

To add a fuzzing workflow that fuzzes all pull requests to your repo, add the following default configurations to .github/workflows/cflite_pr.yml:

name: ClusterFuzzLite PR fuzzing
on:
pull_request:
paths:
‘**’
permissions: read-all
jobs:
PR:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer:
– address
# Override this with the sanitizers you want.
# – undefined
# – memory
steps:
name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
sanitizer: ${{ matrix.sanitizer }}
# Optional but recommended: used to only run fuzzers that are affected
# by the PR.
# See later section on “Git repo for storage”.
# storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
# storage-repo-branch: main # Optional. Defaults to “main”
# storage-repo-branch-coverage: gh-pages # Optional. Defaults to “gh-pages”.
name: Run Fuzzers (${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 600
mode: ‘code-change’
sanitizer: ${{ matrix.sanitizer }}
# Optional but recommended: used to download the corpus produced by
# batch fuzzing.
# See later section on “Git repo for storage”.
# storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
# storage-repo-branch: main # Optional. Defaults to “main”
# storage-repo-branch-coverage: gh-pages # Optional. Defaults to “gh-pages”.

Optionally, edit the following fields to customize your settings:

  • sanitizers Change or enable more sanitizers.
  • fuzz-seconds Change the amount of time spent fuzzing.
  • storage-repostorage-repo-branchstorage-repo-branch-coverage Enable a storage repo (not necessary for initial runs, but a useful feature discussed later on).

Merge this file into your GitHub repo. To test the workflow, open a pull request to your project.

To download crashes from code change fuzzing, please see the section on downloading artifacts.

Batch fuzzing

Batch fuzzing enables continuous, regular fuzzing on your latest HEAD and allows a corpus of inputs to build up over time, which greatly improves the effectiveness of fuzzing. Batch fuzzing can be run on a cron schedule.

To enable batch fuzzing, add the following to .github/workflows/cflite_batch.yml:

name: ClusterFuzzLite batch fuzzing
on:
schedule:
cron: ‘0 0/6 * * *’ # Every 6th hour. Change this to whatever is suitable.
permissions: read-all
jobs:
BatchFuzzing:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer:
address
# Override this with the sanitizers you want.
# – undefined
# – memory
steps:
name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
sanitizer: ${{ matrix.sanitizer }}
name: Run Fuzzers (${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 3600
mode: ‘batch’
sanitizer: ${{ matrix.sanitizer }}
# Optional but recommended: For storing certain artifacts from fuzzing.
# See later section on “Git repo for storage”.
# storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
# storage-repo-branch: main # Optional. Defaults to “main”
# storage-repo-branch-coverage: gh-pages # Optional. Defaults to “gh-pages”.

Optionally, edit the following fields to customize your settings:

  • cron Change how frequently batch fuzzing is run. See GitHub’s documentation on this.
  • sanitizers Change or enable more sanitizers.
  • fuzz-seconds Change the amount of time spent fuzzing.
  • storage-repostorage-repo-branchstorage-repo-branch-coverage Enable a storage repo.

Though not recommended, you can configure batch fuzzing to run on each push to your main branch, change the on field to:

on:
push:
branches:
main # Use your actual default branch here.

Make sure to change branches to the actual branch(es) you wish to fuzz.

NOTE: If batch fuzzing is running, you must also run corpus pruning.

Continuous builds

The continuous build task causes a build to be triggered and uploaded as a GitHub Actions artifact whenever a new push is done to main/default branch.

Continuous builds are used when a crash is found during PR fuzzing to determine whether the crash was newly introduced. If the crash is not novel, PR fuzzing will not report it. This means that there will be fewer unrelated failures when running code change fuzzing.

Disclaimer: If your builds are large they may exceed the free GitHub actions quotas. In this case it’s recommended to not enable continuous builds.

To set up continuous builds, add the following to .github/workflows/cflite_build.yml:

name: ClusterFuzzLite continuous builds
on:
push:
branches:
main # Use your actual default branch here.
permissions: read-all
jobs:
Build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer:
address
# Override this with the sanitizers you want.
# – undefined
# – memory
steps:
name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
sanitizer: ${{ matrix.sanitizer }}
uplo
ad-build: true

NOTE: Be sure to change the branches field to match your project’s main branch.

If you plan to use multiple sanitizers, add them all to the sanitizer field (to enable builds for each sanitizer)

Corpus pruning

Corpus pruning minimizes the corpus produced by batch fuzzing by removing redundant items while keeping the same code coverage. To enable this, add the following to .github/workflows/cflite_cron.yml:

name: ClusterFuzzLite cron tasks
on:
schedule:
cron: ‘0 0 * * *’ # Once a day at midnight.
permissions: read-all
jobs:
Pruning:
runs-on: ubuntu-latest
steps:
name: Build Fuzzers
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
name: Run Fuzzers
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 600
mode: ‘prune’
# Optional but recommended.
# See later section on “Git repo for storage”.
# storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
# storage-repo-branch: main # Optional. Defaults to “main”
# storage-repo-branch-coverage: gh-pages # Optional. Defaults to “gh-pages”.

Optionally, edit the following field to customize your settings:

  • storage-repostorage-repo-branchstorage-repo-branch-coverage Enable a storage repo.

Coverage reports

To generate periodic coverage reports, add the following to the jobs field in .github/workflows/cflite_cron.yml after the Pruning job:

Optionally, edit the following fields to view coverage reports at https://USERNAME.github.io/STORAGE-REPO-NAME/coverage/latest/report/linux/report.html:

  • set storage-repo (instructions here)
  • set storage-repo-branch-coverage to “gh-pages” (the default)
  • set owner and storage-repo-name to the appropriate values for your storage repo

Extra configuration

Git repo for storage

It’s optional but recommended that you set up a separate git repo for storing corpora and coverage reports. The storage repo will make corpus management better in some scenarios and will allow you to view coverage reports on the web rather than downloading them as artifacts.

An empty repository for this is sufficient.

You’ll need to set up a personal access token with write permissions to the storage repo and add it as a repository secret called PERSONAL_ACCESS_TOKEN. This is because the default GitHub auth token is not able to write to other repositories. Note: if you run into issues with the storage repo, you may have accidentally set the secret as an environment secret instead of a repository secret.

If you would like PR fuzzing to run only the fuzzers affected by the current change, you’ll need to add these same options to the “Build Fuzzers” step above. The “affected fuzzers” are determined by using coverage reports.

If a storage repo isn’t specified, corpora and coverage reports will be uploaded as GitHub artifacts instead.

Private repos

In order for ClusterFuzzLite to use private repos, the GitHub token needs to be passed to the build and run steps. This token is automaticallly set by GitHub actions so no extra action is required from you except passing it to build fuzzers and run fuzzers in each workflow file:

Google Cloud Build

This document explains how to set up ClusterFuzzLite on Google Cloud Build (GCB). This document assumes the reader has set up builds using GCB before. Documentation on using GCB is available here. To get the most of this page, you should have already set up your build integration and read the more high-level document on running ClusterFuzzLite. This document also assumes your code is hosted on GitHub, but it should be mostly applicable if your code is hosted elsewhere.

We recommend having separate workflow files for each part of ClusterFuzzLite:

  • .clusterfuzzlite/cflite_build.yml (for building/continuous fuzzing)
  • .clusterfuzzlite/cflite_pr.yml (for code change (pull request) fuzzing)
  • .clusterfuzzlite/cflite_batch.yml (for batch fuzzing)
  • .clusterfuzzlite/cflite_prune.yml (for corpus pruning)
  • .clusterfuzzlite/cflite_coverage.yml (for coverage reports)

First, you must create a Google Cloud Storage Bucket. This will be refered to as <your-cloud-bucket> in the config examples in this document. The bucket will be used to store crashes, builds, corpora, and coverage reports. You will also need to set the REPOSITORY environment variable. The value for REPOSITORY will be denoted by <your-repo-name> in this document. Note that this must be the same as the directory in /src where your project’s code is located. Also note that the configuration examples set the environment variable: CFL_PLATFORM this value is general for all GCB users. Do not change it.

Continuous builds

Continuous builds are used whenever a crash is found during code change fuzzing to determine if this crash was newly introduced.

Add the following to .clusterfuzzlite/cflite_build.yml:

steps:
name: gcr.io/oss-fuzz-base/clusterfuzzlite-build-fuzzers:v1
env:
– ‘CLOUD_BUCKET=’
– ‘REPOSITORY=’
– ‘SANITIZER=address’ # This can be changed to other sanitizers you use.
– ‘LANGUAGE=c++’ # Change this to your project’s language.
– ‘UPLOAD_BUILD=True’
– ‘CFL_PLATFORM=gcb’

Set up a trigger to run this job using the console. Select the “Push to a branch” event and select your repo’s main branch. This trigger will cause a build to be saved for each commit to your repo’s main branch.

Code change fuzzing

To add a fuzzing workflow that runs on all pull requests to your project, add the following to .clusterfuzzlite/cflite_pr.yml:

Set up a trigger to run this workflow on the “pull request” event so that it can fuzz code changes when they are in review. You can set the FUZZ_SECONDS value when running the fuzzers to change the amount of time ClusterFuzzLite will fuzz PRs for.

Batch fuzzing

To enable batch fuzzing, add the following to .clusterfuzzlite/cflite_batch.yml:

This can be run on either pushes to your default branch, but we recommend running it on a cron schedule.

Set up a trigger that runs this workflow manually. Then follow the documentation on making the workflow run on a schedule.

You can set the FUZZ_SECONDS value when running the fuzzers to change the amount of time ClusterFuzzLite will fuzz PRs for.

Corpus pruning

Corpus pruning minimizes a corpus by removing redundant items while keeping the same code coverage. To enable this, add the following to .clusterfuzzlite/cflite_cron.yml:

Coverage reports

Periodic coverage reports can also be generated using the latest corpus. To enable this, add the following to .clusterfuzzlite/cflite_coverage.yml:

To run this workflow periodically: set up a trigger that runs this workflow manually. Then follow the documentation on making the workflow run on a schedule. We recommend scheduling coverage reports to run once a day.

Viewing crashes

Google Cloud Build does not offer an easy way to download files associated with a build. Therefore, to download crashes that were found by ClusterFuzzLite, inspect the logs to find the name of the crash file and then download it from <your-cloud-bucket>/crashes/<fuzzer>/<sanitizer>/<crash-file> where <crash-file> is the name of the crashing input that was found by ClusterFuzzLite, <fuzzer> is the fuzzer that found the crashing input, and <sanitizer> is the sanitizer used to find the crash. Note that these files can be downloaded using a web browser by nagivating to https://console.cloud.google.com/storage/browser/<your-cloud-bucket-without-gs>/crashes/<fuzzer>/<sanitizer> Where <your-cloud-bucket-without-gs> is <your-cloud-bucket> without gs:// at the beginning. For example, if <your-cloud-bucket> is gs://clusterfuzzlite-storage, then <your-cloud-bucket-without-gs> is clusterfuzzlite-storage.

Testing it Out

You can test each of the workflows by triggering the builds manually either using the web interface or on the command line using gcloudgcloud can either be used to submit the build to run on Google Cloud, or you can simulate the build locally using cloud-build-local. If you want to submit the builds to run on Google Cloud manually, please create an empty file named .gcloudignore in the root of your repository or see this github issue because Google Cloud Build will not by default include the .git folder of your repository for manually submitted builds.

Storage Layout

Artifacts produced by ClusterFuzzLite are stored in <your-cloud-bucket>. The bucket has the following layout.

  • Crashes:
  • <your-cloud-bucket>/crashes/<fuzzer>/<sanitizer>/<crash-file>
  • <your-cloud-bucket>/crashes/<fuzzer>/<sanitizer>/<crash-file>.summary (output from crash).