diff options
Diffstat (limited to 'docs/getting-started')
-rw-r--r-- | docs/getting-started/bug_disclosure_guidelines.md | 6 | ||||
-rw-r--r-- | docs/getting-started/continuous_integration.md | 31 | ||||
-rw-r--r-- | docs/getting-started/new-project-guide/bazel.md | 64 | ||||
-rw-r--r-- | docs/getting-started/new-project-guide/go_lang.md | 11 | ||||
-rw-r--r-- | docs/getting-started/new-project-guide/jvm_lang.md | 173 | ||||
-rw-r--r-- | docs/getting-started/new-project-guide/python_lang.md | 9 | ||||
-rw-r--r-- | docs/getting-started/new_project_guide.md | 34 |
7 files changed, 257 insertions, 71 deletions
diff --git a/docs/getting-started/bug_disclosure_guidelines.md b/docs/getting-started/bug_disclosure_guidelines.md index f82a75100..e5a76ef2c 100644 --- a/docs/getting-started/bug_disclosure_guidelines.md +++ b/docs/getting-started/bug_disclosure_guidelines.md @@ -12,12 +12,12 @@ Following [Google's standard disclosure policy](https://googleprojectzero.blogsp OSS-Fuzz will adhere to following disclosure principles: - **Deadline**. After notifying project authors, we will open reported - issues to the public in 90 days, or 30 days after the fix is released - (whichever comes earlier). + issues to the public in 90 days, or after the fix is released (whichever + comes earlier). - **Weekends and holidays**. If a deadline is due to expire on a weekend, the deadline will be moved to the next normal work day. - **Grace period**. We have a 14-day grace period. If a 90-day deadline expires but the upstream engineers let us know before the deadline that a patch is scheduled for release on a specific day within 14 days following the deadline, the public disclosure will be delayed until the availability - of the patch.
\ No newline at end of file + of the patch. diff --git a/docs/getting-started/continuous_integration.md b/docs/getting-started/continuous_integration.md index bb3f7e107..88e6e4b15 100644 --- a/docs/getting-started/continuous_integration.md +++ b/docs/getting-started/continuous_integration.md @@ -74,13 +74,13 @@ jobs: uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'example' - dry-run: false + language: c++ - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'example' + language: c++ fuzz-seconds: 600 - dry-run: false - name: Upload Crash uses: actions/upload-artifact@v1 if: failure() && steps.build.outcome == 'success' @@ -93,8 +93,16 @@ jobs: ### Optional configuration #### Configurable Variables + +`language`: (optional) The language your target program is written in. Defaults +to `c++`. This should be the same as the value you set in `project.yaml`. See +[this explanation]({{ site.baseurl }}//getting-started/new-project-guide/#language) +for more details. + `fuzz-time`: Determines how long CIFuzz spends fuzzing your project in seconds. -The default is 600 seconds. The GitHub Actions max run time is 21600 seconds (6 hours). +The default is 600 seconds. The GitHub Actions max run time is 21600 seconds (6 +hours). This variable is only meaningful when supplied to the `run_fuzzers` +action, not the `build_fuzzers` action. `dry-run`: Determines if CIFuzz surfaces errors. The default value is `false`. When set to `true`, CIFuzz will never report a failure even if it finds a crash in your project. @@ -103,7 +111,8 @@ make sure to set the dry-run parameters in both the `Build Fuzzers` and `Run Fuz `allowed-broken-targets-percentage`: Can be set if you want to set a stricter limit for broken fuzz targets than OSS-Fuzz's check_build. Most users should -not set this. +not set this. This value is only meaningful when supplied to the `run_fuzzers` +action, not the `build_fuzzers` action. `sanitizer`: Determines a sanitizer to build and run fuzz targets with. The choices are `'address'`, `'memory'` and `'undefined'`. The default is `'address'`. It is important to note that the `Build Fuzzers` @@ -128,14 +137,14 @@ jobs: uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'example' - dry-run: false + language: c++ sanitizer: ${{ matrix.sanitizer }} - name: Run Fuzzers (${{ matrix.sanitizer }}) uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'example' + language: c++ fuzz-seconds: 600 - dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash uses: actions/upload-artifact@v1 @@ -175,13 +184,13 @@ jobs: uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'example' - dry-run: false + language: c++ - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'example' + language: c++ fuzz-seconds: 600 - dry-run: false - name: Upload Crash uses: actions/upload-artifact@v1 if: failure() && steps.build.outcome == 'success' @@ -213,9 +222,9 @@ The results of CIFuzz can be found in two different places. 1. When a crash is found by CIFuzz the Upload Artifact event is triggered. 1. This will cause a pop up in the right hand corner, allowing you to download a zip file called `artifacts`. - 1. `artifacts` contains two files: - * `test_case` - a test case that can be used to reproduce the crash. - * `bug_summary` - the stack trace and summary of the crash. + 1. `artifacts` contains two files for each crash: + * A test case that can be used to reproduce the crash. + * The sanitizer stack trace of the crash. ![Finding uploaded artifacts](../images/artifacts.png) diff --git a/docs/getting-started/new-project-guide/bazel.md b/docs/getting-started/new-project-guide/bazel.md index 4ad179d86..45b942fee 100644 --- a/docs/getting-started/new-project-guide/bazel.md +++ b/docs/getting-started/new-project-guide/bazel.md @@ -3,7 +3,7 @@ layout: default title: Integrating a Bazel project parent: Setting up a new project grand_parent: Getting started -nav_order: 4 +nav_order: 5 permalink: /getting-started/new-project-guide/bazel/ --- @@ -36,10 +36,9 @@ test artifacts in the OSS-Fuzz format. Each `//path/to:fuzz_test` fuzz test target automatically has a `//path/to:fuzz_test_oss_fuzz` packaging target that (a) builds the fuzz test using the instrumentation and engine library specified in the OSS-Fuzz environment variables, and (b) generates an archive containing -the binary and its associated artifacts (corpus, dictionary, etc.). Using the -`_oss_fuzz` target substantially simplifies the `build.sh` script, which only -needs to copy the build artifacts from `bazel-bin/` to the `${OUT}/` directory. -The next section explains this process in more detail. +the binary and its associated artifacts (corpus, dictionary, etc.). Moreover, +OSS-Fuzz provides a standard tool to automatically process these targets, +substantially simplifying the `build.sh` script (see below). [rules-fuzzing-usage]: https://github.com/bazelbuild/rules_fuzzing#using-the-rules-in-your-project @@ -61,7 +60,7 @@ Only C++ projects are currently supported. Since the OSS-Fuzz target builds the fuzz test using the instrumentation and engine specified in the OSS-Fuzz environment variables, all the engine and sanitizer configurations supported in the `project.yaml` file are automatically -supported by the `_oss_fuzz` packaging rule, too. +supported by the fuzzing rules. ### Dockerfile @@ -75,43 +74,24 @@ file in your repository root with the desired version string. ### build.sh -Your `build.sh` script essentially needs to perform three tasks: (1) selecting +Your `build.sh` script essentially needs to perform three steps: (1) selecting which fuzz tests to build, (2) building their OSS-Fuzz package targets in the right configuration, and (3) copying the build artifacts to the `${OUT}/` destination. -For the first step, you can use the "bazel query" command for the most -flexibility. Each fuzz test has the `"fuzz-test"` tag, which you can query. You -may also perform additional filtering. We recommend using the `"no-oss-fuzz"` -tag to opt-out particular fuzz tests if they are a work in progress or -test-only. - -The complete query command would look as follows ([example][example-query]): - -```sh -declare -r QUERY=' - let all_fuzz_tests = attr(tags, "fuzz-test", "//...") in - $all_fuzz_tests - attr(tags, "no-oss-fuzz", $all_fuzz_tests) -' -declare -r OSS_FUZZ_TESTS="$(bazel query "${QUERY}" | sed "s/$/_oss_fuzz/")" -``` - -Building the `_oss_fuzz` targets requires setting the engine and instrumentation -options. We recommend creating a `--config=oss-fuzz` configuration in your -`.bazelrc` file ([example][example-bazelrc]), so you can directly invoke -`bazel build --config=oss-fuzz` in your build script ([example][example-build]). - -If all goes well, `bazel-bin/` will contain an `_oss_fuzz.tar` archive for each -fuzz test built. You need to traverse each archive and extract it in the -`${OUT}/` directory ([example][example-copy]): - -```sh -for oss_fuzz_archive in $(find bazel-bin/ -name '*_oss_fuzz.tar'); do - tar -xvf "${oss_fuzz_archive}" -C "${OUT}" -done -``` - -[example-query]: https://github.com/google/oss-fuzz/blob/b19e7001928b08f9ae8fd3c017688cd5edf96cb2/projects/bazel-rules-fuzzing-test/build.sh#L27-L37 -[example-bazelrc]: https://github.com/bazelbuild/rules_fuzzing/blob/f6062a88d83463e2900e47bc218547ba046dad44/.bazelrc#L56-L58 -[example-build]: https://github.com/google/oss-fuzz/blob/b19e7001928b08f9ae8fd3c017688cd5edf96cb2/projects/bazel-rules-fuzzing-test/build.sh#L43-L45 -[example-copy]: https://github.com/google/oss-fuzz/blob/b19e7001928b08f9ae8fd3c017688cd5edf96cb2/projects/bazel-rules-fuzzing-test/build.sh#L50-L52 +OSS-Fuzz provides a +[`bazel_build_fuzz_tests`](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/bazel_build_fuzz_tests) +tool that implements these steps in a standard way, so in most cases your +build script only needs to invoke this command with no arguments. + +If necessary, the behavior of the tool can be customized though a set of +environment variables. The most common are: + +* `BAZEL_EXTRA_BUILD_FLAGS` are extra build flags passed on the Bazel command + line. +* `BAZEL_FUZZ_TEST_TAG` and `BAZEL_FUZZ_TEST_EXCLUDE_TAG` can be overriden to + specify which target tags to use when determining what fuzz tests to include. + By default, the tool selects all the fuzz tests except for those tagged as + `"no-oss-fuzz"`. +* `BAZEL_FUZZ_TEST_QUERY` overrides the Bazel query the tool uses to identify + the fuzz tests to build, if the tag-based approach is not sufficient. diff --git a/docs/getting-started/new-project-guide/go_lang.md b/docs/getting-started/new-project-guide/go_lang.md index 62fde91d6..600a66665 100644 --- a/docs/getting-started/new-project-guide/go_lang.md +++ b/docs/getting-started/new-project-guide/go_lang.md @@ -60,21 +60,16 @@ sanitizers: ### Dockerfile The OSS-Fuzz builder image has the latest stable release of Golang installed. In -order to install dependencies of your project, add `RUN go get ...` command to +order to install dependencies of your project, add `RUN git clone ...` command to your Dockerfile. [Example](https://github.com/google/oss-fuzz/blob/356f2b947670b7eb33a1f535c71bc5c87a60b0d1/projects/syzkaller/Dockerfile#L23): ```dockerfile # Dependency for one of the fuzz targets. -RUN go get github.com/ianlancetaylor/demangle +RUN git clone --depth 1 https://github.com/ianlancetaylor/demangle ``` -In the case you are using modules, the best practice is to `git clone` the repository into the expected `$GOPATH/src` directory. - -A usage example from go-coredns project is -```dockerfile -RUN git clone --depth 1 https://github.com/coredns/coredns $GOPATH/src/github.com/coredns/coredns -``` +go-fuzz will then automatically download the dependencies based on the go.mod file ### build.sh diff --git a/docs/getting-started/new-project-guide/jvm_lang.md b/docs/getting-started/new-project-guide/jvm_lang.md new file mode 100644 index 000000000..19e4ecbfe --- /dev/null +++ b/docs/getting-started/new-project-guide/jvm_lang.md @@ -0,0 +1,173 @@ +--- +layout: default +title: Integrating a Java/JVM project +parent: Setting up a new project +grand_parent: Getting started +nav_order: 4 +permalink: /getting-started/new-project-guide/jvm-lang/ +--- + +# Integrating a Java/JVM project +{: .no_toc} + +- TOC +{:toc} +--- + +The process of integrating a project written in Java or any other language +running on the Java Virtual Machine (JVM) with OSS-Fuzz is very similar to the +general +[Setting up a new project]({{ site.baseurl }}/getting-started/new-project-guide/) +process. The key specifics of integrating a JVM project are outlined below. + +## Jazzer + +Java fuzzing in OSS-Fuzz depends on +[Jazzer](https://github.com/CodeIntelligenceTesting/jazzer), which is +pre-installed on the OSS-Fuzz base docker images. As Jazzer operates directly +on the bytecode level, it can be applied to any project written in a JVM-based +language. More information on how Jazzer fuzz targets look like can be found in +its +[README's Usage section](https://github.com/CodeIntelligenceTesting/jazzer#usage). + +## Project files + +### Example project + +We recommend viewing +[json-sanitizer](https://github.com/google/oss-fuzz/tree/master/projects/json-sanitizer) +as an example of a simple Java-only fuzzing project. Additional examples, +including one for a Java project with native dependencies, are part of the +[java-example](https://github.com/google/oss-fuzz/tree/master/projects/java-example) +project. + +### project.yaml + +The `language` attribute must be specified as follows: + +```yaml +language: jvm +``` + +The only supported fuzzing engine is libFuzzer (`libfuzzer`). So far the only +supported sanitizer is AddressSanitizer (`address`), which needs to be +specified explicitly even for pure Java projects. + +```yaml +fuzzing_engines: + - libfuzzer +sanitizers: + - address +``` + +### Dockerfile + +The OSS-Fuzz base Docker images already come with OpenJDK 15 pre-installed. If +you need Maven to build your project, you can install it by adding the following +line to your Dockerfile: + +```docker +RUN apt-get update && apt-get install -y maven +``` + +Apart from this, you should usually not need to do more than to clone the +project, set a `WORKDIR`, and copy any necessary files, or install any +project-specific dependencies here as you normally would. + +### Fuzzers + +In the simplest case, every fuzzer consists of a single Java file with a +filename matching `*Fuzzer.java` and no `package` directive. An example fuzz +target could thus be a file `ExampleFuzzer.java` with contents: + +```java +public class ExampleFuzzer { + public static void fuzzerTestOneInput(byte[] input) { + ... + // Call a function of the project under test with arguments derived from + // input and throw an exception if something unwanted happens. + ... + } +} +``` + +### build.sh + +For JVM projects, `build.sh` does need some more significant modifications +over C/C++ projects. Below is an annotated example build script for a +Java-only project with single-file fuzz targets as described above: + +```sh +# Step 1: Build the project + +# Build the project .jar as usual, e.g. using Maven. +mvn package +# In this example, the project is built with Maven, which typically includes the +# project version into the name of the packaged .jar file. The version can be +# obtained as follows: +CURRENT_VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \ +-Dexpression=project.version -q -DforceStdout) +# Copy the project .jar into $OUT under a fixed name. +cp "target/sample-project-$CURRENT_VERSION.jar" $OUT/sample-project.jar + +# Specify the projects .jar file(s), separated by spaces if there are multiple. +PROJECT_JARS="sample-project.jar" + +# Step 2: Build the fuzzers (should not require any changes) + +# The classpath at build-time includes the project jars in $OUT as well as the +# Jazzer API. +BUILD_CLASSPATH=$(echo $PROJECT_JARS | xargs printf -- "$OUT/%s:"):$JAZZER_API_PATH + +# All .jar and .class files lie in the same directory as the fuzzer at runtime. +RUNTIME_CLASSPATH=$(echo $PROJECT_JARS | xargs printf -- "\$this_dir/%s:"):\$this_dir + +for fuzzer in $(find $SRC -name '*Fuzzer.java'); do + fuzzer_basename=$(basename -s .java $fuzzer) + javac -cp $BUILD_CLASSPATH $fuzzer + cp $SRC/$fuzzer_basename.class $OUT/ + + # Create an execution wrapper that executes Jazzer with the correct arguments. + echo "#!/bin/sh +# LLVMFuzzerTestOneInput for fuzzer detection. +this_dir=\$(dirname \"\$0\") +LD_LIBRARY_PATH=\"$JVM_LD_LIBRARY_PATH\":\$this_dir \ +\$this_dir/jazzer_driver --agent_path=\$this_dir/jazzer_agent_deploy.jar \ +--cp=$RUNTIME_CLASSPATH \ +--target_class=$fuzzer_basename \ +--jvm_args=\"-Xmx2048m\" \ +\$@" > $OUT/$fuzzer_basename + chmod u+x $OUT/$fuzzer_basename +done +``` + +## FuzzedDataProvider + +Jazzer provides a `FuzzedDataProvider` that can simplify the task of creating a +fuzz target by translating the raw input bytes received from the fuzzer into +useful primitive Java types. Its functionality is similar to +`FuzzedDataProviders` available in other languages, such as +[Python](https://github.com/google/atheris#fuzzeddataprovider) and +[C++](https://github.com/google/fuzzing/blob/master/docs/split-inputs.md). + +On OSS-Fuzz, the required library is available in the base docker images under +the path `$JAZZER_API_PATH`, which is added to the classpath by the example +build script shown above. Locally, the library can be obtained from +[Maven Central](https://search.maven.org/search?q=g:com.code-intelligence%20a:jazzer-api). + +A fuzz target using the `FuzzedDataProvider` would look as follows: + +```java +import com.code_intelligence.jazzer.api.FuzzedDataProvider; + +public class ExampleFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + int number = data.consumeInt(); + String string = data.consumeRemainingAsString(); + // ... + } +} +``` + +For a list of convenience methods offered by `FuzzedDataProvider`, consult its +[javadocs](https://codeintelligencetesting.github.io/jazzer-api/com/code_intelligence/jazzer/api/FuzzedDataProvider.html). diff --git a/docs/getting-started/new-project-guide/python_lang.md b/docs/getting-started/new-project-guide/python_lang.md index 14208e300..da147803a 100644 --- a/docs/getting-started/new-project-guide/python_lang.md +++ b/docs/getting-started/new-project-guide/python_lang.md @@ -31,7 +31,7 @@ docker images. ### Example project -We recommending viewing [ujson](https://github.com/google/oss-fuzz/tree/master/projects/ujson) as an +We recommend viewing [ujson](https://github.com/google/oss-fuzz/tree/master/projects/ujson) as an example of a simple Python fuzzing project, with both plain-Atheris and Atheris + Hypothesis harnesses. @@ -112,14 +112,17 @@ or [by using test functions as fuzz harnesses](https://hypothesis.readthedocs.io failures in the test reveal problems with the system under test that could not have been revealed by direct fuzzing of that system. -You also get integrated test-case reduction for free - meaning that it's trivial to -report a canonical minimal example for each distinct failure discovered while fuzzing! +We recommend using the [`hypothesis write`](https://hypothesis.readthedocs.io/en/latest/ghostwriter.html) +command to generate a starter fuzz harness. This "ghostwritten" code may be usable as-is, +or provide a useful template for writing more specific tests. See [here for the core "strategies"](https://hypothesis.readthedocs.io/en/latest/data.html), for arbitrary data, [here for Numpy + Pandas support](https://hypothesis.readthedocs.io/en/latest/numpy.html), or [here for a variety of third-party extensions](https://hypothesis.readthedocs.io/en/latest/strategies.html) supporting everything from protobufs, to jsonschemas, to networkx graphs or geojson or valid Python source code. +Hypothesis' integrated test-case reduction also makes it trivial to report a canonical minimal +example for each distinct failure discovered while fuzzing - just run the test function! To use Hypothesis in OSS-Fuzz, install it in your Dockerfile with diff --git a/docs/getting-started/new_project_guide.md b/docs/getting-started/new_project_guide.md index 64d4b8029..d2a7d805b 100644 --- a/docs/getting-started/new_project_guide.md +++ b/docs/getting-started/new_project_guide.md @@ -97,6 +97,7 @@ Programming language the project is written in. Values you can specify include: * [`go`]({{ site.baseurl }}//getting-started/new-project-guide/go-lang/) * [`rust`]({{ site.baseurl }}//getting-started/new-project-guide/rust-lang/) * [`python`]({{ site.baseurl }}//getting-started/new-project-guide/python-lang/) +* [`jvm` (Java, Kotlin, Scala and other JVM-based languages)]({{ site.baseurl }}//getting-started/new-project-guide/jvm-lang/) ### primary_contact, auto_ccs {#primary} The primary contact and list of other contacts to be CCed. Each person listed gets access to ClusterFuzz, including crash reports and fuzzer statistics, and are auto-cced on new bugs filed in the OSS-Fuzz @@ -148,7 +149,8 @@ homepage]({{ site.baseurl }}/further-reading/clusterfuzz#web-interface). ### architectures (optional) {#architectures} The list of architectures to fuzz on. ClusterFuzz supports fuzzing on x86_64 (aka x64) by default. -However you can also fuzz using AddressSanitizer and libFuzzer on i386 (aka x86, or 32 bit) by specifying "x86_64" and "i386" in "architectures" like this: +Some projects can benefit from i386 fuzzing. OSS-Fuzz will build and run +AddressSanitizer with libFuzzer on i386 by doing the following: ```yaml architectures: @@ -192,7 +194,6 @@ For most projects, the image is simple: ```docker FROM gcr.io/oss-fuzz-base/base-builder # base image with clang toolchain RUN apt-get update && apt-get install -y ... # install required packages to build your project -RUN go get ... # install dependencies to build your Go project RUN git clone <git_url> <checkout_dir> # checkout all sources needed to build your project WORKDIR <checkout_dir> # current directory for the build script COPY build.sh fuzzer.cc $SRC/ # copy build script and other fuzzer files in src dir @@ -245,6 +246,30 @@ If your project is written in Go, check out the [Integrating a Go project]({{ si alphanumeric characters, underscore(_) or dash(-). Otherwise, they won't run on our infrastructure. 3. Don't remove source code files. They are needed for code coverage. +### Temporarily disabling code instrumentation during builds + +Sometimes not every 3rd party library might be needed to be instrumented or +tools are being compiled that just support the target built. + +If for any reasons part of the build process should not be instrumented +then the following code snippit can be used for this: + +``` +CFLAGS_SAVE="$CFLAGS" +CXXFLAGS_SAVE="$CXXFLAGS" +unset CFLAGS +unset CXXFLAGS +export AFL_NOOPT=1 + +# +# build commands here that should not result in instrumented code. +# + +export CFLAGS="${CFLAGS_SAVE}" +export CXXFLAGS="${CXXFLAGS_SAVE}" +unset AFL_NOOPT +``` + ### build.sh script environment When your build.sh script is executed, the following locations are available within the image: @@ -334,7 +359,8 @@ generated from the previous `run_fuzzer` step in your local corpus directory. $ python infra/helper.py coverage $PROJECT_NAME --fuzz-target=<fuzz_target> --corpus-dir=<path-to-temp-corpus-dir> ``` -Please refer to +You may need to run `python infra/helper.py pull_images` to use the latest +coverage tools. Please refer to [code coverage]({{ site.baseurl }}/advanced-topics/code-coverage/) for detailed information on code coverage generation. @@ -421,7 +447,7 @@ via GitHub. Please include copyright headers for all files checked in to oss-fuzz: ``` -# Copyright 2020 Google LLC +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. |