Skip to content

Latest commit

 

History

History
120 lines (78 loc) · 6.46 KB

File metadata and controls

120 lines (78 loc) · 6.46 KB

Chronos: rebuilding OSS-Fuzz harnesses using cached builds

Chronos is a utility tooling to enable fast re-building of OSS-Fuzz projects and analysis of projects' testing infrastructure. This is used by projects, e.g. OSS-Fuzz-gen to help speed up valuation processes during fuzzing harness generation.

At the core, Chronos relies on caching containers after project build, in order to enable fast rebuilding of a project following minor patches, and also enable running of the tests in a given project. To support this, Chronos creates a snapshot of a the docker container given project post build completion. This means that all .o files, generated configuations etc. persist in the docker container. These artifacts are then leverage for future "replay builds" where only a minor part of the project has changed, e.g. due to some patching on the project. This patching could be e.g. minor adjustments to the fuzzing harness source code e.g. by oss-fuzz-gen.

As such, at the core of Chronos are cached containers that are generated by taking a snapshot of the container of a project post project build.

Chronos is focused on two features, rebuilding projects fast and running the tests of a given project.

Chronos features: fast rebuilding and running the tests of a project

CLI interface for Chronos

The default route to validating Chronos is using the CLI available in infra/experimental/chronos/manager.py

Chronos feature: Fast rebuilding

Chronos enables rebuilding projects efficiently in contexts where only a small patch needs to be evalualted in the target. This is achieved by running a replay build script in the build container, similarly to how a regular build_fuzzers command would run, but with the caveat that the replay build script only performs a subset of the operations of the original build.sh.

The replay build scripts are constructed in two ways: manually or automatically.

Option 1: Automated rebuilds

Chronos support automated rebuilding. This is meant as a generic mechanism to enable Chronos support for projects by default. This is achieved by:

  1. Calling into a replay_build.sh script during the building inside the container here
  2. The replay_build.sh calls into make_build_replayable.py: here
  3. make_build_replayable.py adjusts the build environment to wrap around common commands, to avoid performing a complete run of build.sh: here.

The automated rebuilding works in combination with Ccache, in order to facilitate cachine of e.g. .o files. This means that during rebuild mode as long as we have a cacche, we don't need to e.g. run configure again and will only have to rebuild the changed source code.

Option 2: Manually provided replay builds

replay_build.sh above, is simply just a wrapper script around build.sh that aims to enable fast rebuilding of the project. This replay_build.sh can, however, be overwritten in the Dockerfile of the project's builder image to support a custom approach to fast rebuilding. Two examples of this is php and ffmpeg.

Providing a manual replay_build.sh is likely more efficient at build time and can help speed up the process. Automated replay build scripts can also be erroneous.

Testing the validity of a replay build

The Chronos manager can use the manager.py to validate the validity of a replay build for a given project:

python3 infra/experimental/chronos/manager.py check-test tinyobjloader

If the above command fails for the relevant project, then the replay build feature does not work for the given project.

Chronos feature: Running tests of a project

The second part of Chronos is a feature to enable running the tests of a given project. This is done by way of a script run_tests.sh. Samples of this script include jsonnet and tinyobjloader.

Run tests constraints

  1. The run_tests.sh main task is to run the tests of a project and return 0 upon success and non-null otherwise.
  2. The run_tests.sh script must leave the main repository in the state as it was prior to the execution of run_tests.sh relative to git diff (or similar diff features of other version control systems).

Testing the validity of run_tests.sh

The Chronos manager can use the manager.py to validate the validity of a run_tests.sh script:

python3 infra/experimental/chronos/manager.py check-tests json-c

Constraints imposed on replay_build.sh and run_tests.sh

At the core of chronos are the two scripts replay_build.sh and run_tests.sh. We have a default mechanism for replay_build.sh so it's not strictly necessary to have a custom one, although it will likely improve speed and maybe correctness by providing one.

There are three stages of the Chronos workflow:

  1. The cached containers represent the state of a build container after a successful project build.
  2. The replay_build.sh is able to rebuild a given project from the state of a cached container.
  3. The run_tests.sh script is able to run the tests of a given project. This should be able to succeed following the running of a replay_build.sh.

The stages (2) and (3) must both support running without network connectivity. Specifically, this means that the replay_build.sh must not do tasks e.g. fetch dependencies, download corpus, or anything of this nature. Similarly, the run_tests.sh must be able to operate completely in a closed network environment.

Pre-built images.

Chronos cached images are build daily, and pre-built images are available at:

  • us-central1-docker.pkg.dev/oss-fuzz/oss-fuzz-gen/<PROJECT>-ofg-cached-address
  • us-central1-docker.pkg.dev/oss-fuzz/oss-fuzz-gen/<PROJECT>-ofg-cached-coverage

They can be used as drop-in replacements for the usual gcr.io/oss-fuzz/<PROJECT> images.