gitlab-org--gitlab-foss/doc/user/application_security/coverage_fuzzing/index.md

6.9 KiB

stage group info type
Secure Fuzz Testing To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers reference, howto

Coverage Guided Fuzz Testing (ULTIMATE)

Introduced in GitLab Ultimate 13.2 as an Alpha feature.

GitLab allows you to add coverage-guided fuzz testing to your pipelines. This helps you discover bugs and potential security issues that other QA processes may miss. Coverage-guided fuzzing sends random inputs to an instrumented version of your application in an effort to cause unexpected behavior, such as a crash. Such behavior indicates a bug that you should address.

We recommend that you use fuzz testing in addition to the other security scanners in GitLab Secure and your own test processes. If you're using GitLab CI/CD, you can run your coverage guided fuzz tests as part your CI/CD workflow. You can take advantage of Coverage Guided Fuzzing by including the CI job in your existing .gitlab-ci.yml file.

Supported fuzzing engines and languages

GitLab supports these languages through the fuzzing engine listed for each. We currently provide a Docker image for apps written in Go, but you can test the other languages below by providing a Docker image with the fuzz engine to run your app.

Language Fuzzing Engine Example
C/C++ libFuzzer
GoLang go-fuzz (libFuzzer support)
Rust cargo-fuzz (libFuzzer support)

Configuration

To enable fuzzing, you must include the Coverage-Fuzzing.gitlab-ci.yml template provided as part of your GitLab installation.

To do so, add the following to your .gitlab-ci.yml file:

include:
  - template: Coverage-Fuzzing.gitlab-ci.yml

The included template makes available the hidden job .fuzz_base, which you must extend for each of your fuzz targets. Each fuzz target must have a separate job. For example, the go-fuzzing-example project contains one job that extends .fuzz_base for its single fuzz target.

Note that the hidden job .fuzz_base uses several YAML keys that you must not override in your own job. If you include these keys in your own job, you must copy their original content. These keys are:

  • before_script
  • artifacts
  • rules

The my_fuzz_target job (the separate job for your fuzz target) does the following:

  • Extends .fuzz_base.
  • Compiles the fuzz target with go-fuzz.
  • Runs the target with the gitlab-cov-fuzz command, which is available to each job that extends .fuzz_base.
  • Runs on a fuzz stage that usually comes after a test stage.

The gitlab-cov-fuzz is a command-line tool that runs the instrumented application. It parses and analyzes the exception information that the fuzzer outputs. It also downloads the corpus and crash events from previous pipelines automatically. This helps your fuzz targets build on the progress of previous fuzzing jobs. The parsed crash events and data are written to gl-coverage-fuzzing-report.json.

Artifacts

Each fuzzing step outputs these artifacts:

  • gl-coverage-fuzzing-report.json: This file's format may change in future releases.
  • artifacts.zip: This file contains two directories:
    • corpus: Holds all test cases generated by the current and all previous jobs.
    • crashes: Holds all crash events the current job encountered as well as those not fixed in previous jobs.

Types of Fuzzing Jobs

There are two types of jobs:

  • Fuzzing: Standard fuzzing session. You can configure a long session through a user defined timeout.
  • Regression: Run the fuzz targets through the accumulated test cases generated by previous fuzzing sessions plus fixed crashes from previous sessions. This is usually very quick.

Here's our current suggestion for configuring your fuzz target's timeout:

  • Set COVERAGE_FUZZING_BRANCH to the branch where you want to run long-running (async) fuzzing jobs. This is master by default.
  • Use regression or short-running fuzzing jobs for other branches or merge requests.

This suggestion helps find new bugs on the development branch and catch old bugs in merge requests (like unit tests).

You can configure this by passing --regression=false/true to gitlab-cov-fuzz as the Go example shows. Also note that gitlab-cov-fuzz is a wrapper, so you can pass those arguments to configure any option available in the underlying fuzzing engine.

Available variables

Environment variable Description
COVERAGE_FUZZING_BRANCH The branch for long-running fuzzing jobs. The default is master.
CI_SEED_CORPUS Path to a seed corpus directory. The default is empty.

The files in the seed corpus (CI_SEED_CORPUS), if provided, aren't updated unless you commit new files to your Git repository. There's usually no need to frequently update the seed corpus. As part of the GitLab artifacts system, GitLab saves in a corpus directory the new test cases that every run generates. In any subsequent runs, GitLab also reuses the generated corpus together with the seed corpus.

Additional Configuration

The gitlab-cov-fuzz command passes all arguments it receives to the underlying fuzzing engine. You can therefore use all the options available in that fuzzing engine. For more information on these options, see the underlying fuzzing engine's documentation.

Glossary

  • Seed corpus: The set of test cases given as initial input to the fuzz target. This usually speeds up the fuzz target substantially. This can be either manually created test cases or auto-generated with the fuzz target itself from previous runs.
  • Corpus: The set of meaningful test cases that are generated while the fuzzer is running. Each meaningful test case produces new coverage in the tested program. It's advised to re-use the corpus and pass it to subsequent runs.