1--- 2layout: default 3title: Integrating a Java/JVM project 4parent: Setting up a new project 5grand_parent: Getting started 6nav_order: 4 7permalink: /getting-started/new-project-guide/jvm-lang/ 8--- 9 10# Integrating a Java/JVM project 11{: .no_toc} 12 13- TOC 14{:toc} 15--- 16 17The process of integrating a project written in Java or any other language 18running on the Java Virtual Machine (JVM) with OSS-Fuzz is very similar to the 19general 20[Setting up a new project]({{ site.baseurl }}/getting-started/new-project-guide/) 21process. The key specifics of integrating a JVM project are outlined below. 22 23## Jazzer 24 25Java fuzzing in OSS-Fuzz depends on 26[Jazzer](https://github.com/CodeIntelligenceTesting/jazzer), which is 27pre-installed on the OSS-Fuzz base docker images. As Jazzer operates directly 28on the bytecode level, it can be applied to any project written in a JVM-based 29language. More information on how Jazzer fuzz targets look like can be found in 30its 31[README's Usage section](https://github.com/CodeIntelligenceTesting/jazzer#usage). 32 33## Project files 34 35### Example project 36 37We recommend viewing 38[json-sanitizer](https://github.com/google/oss-fuzz/tree/master/projects/json-sanitizer) 39as an example of a simple Java-only fuzzing project. Additional examples, 40including one for a Java project with native dependencies, are part of the 41[java-example](https://github.com/google/oss-fuzz/tree/master/projects/java-example) 42project. 43 44### project.yaml 45 46The `language` attribute must be specified as follows: 47 48```yaml 49language: jvm 50``` 51 52The only supported fuzzing engine is libFuzzer (`libfuzzer`). So far the only 53supported sanitizers are AddressSanitizer (`address`) and 54UndefinedBehaviorSanitizer (`undefined`). For pure Java projects, specify 55just `address`: 56 57```yaml 58fuzzing_engines: 59 - libfuzzer 60sanitizers: 61 - address 62``` 63 64### Dockerfile 65 66The Dockerfile should start by `FROM gcr.io/oss-fuzz-base/base-builder-jvm` 67 68The OSS-Fuzz base Docker images already come with OpenJDK 15 pre-installed. If 69you need Maven to build your project, you can install it by adding the following 70line to your Dockerfile: 71 72```docker 73RUN apt-get update && apt-get install -y maven 74``` 75 76Apart from this, you should usually not need to do more than to clone the 77project, set a `WORKDIR`, and copy any necessary files, or install any 78project-specific dependencies here as you normally would. 79 80### Fuzzers 81 82In the simplest case, every fuzzer consists of a single Java file with a 83filename matching `*Fuzzer.java` and no `package` directive. An example fuzz 84target could thus be a file `ExampleFuzzer.java` with contents: 85 86```java 87public class ExampleFuzzer { 88 public static void fuzzerTestOneInput(byte[] input) { 89 ... 90 // Call a function of the project under test with arguments derived from 91 // input and throw an exception if something unwanted happens. 92 ... 93 } 94} 95``` 96 97### build.sh 98 99For JVM projects, `build.sh` does need some more significant modifications 100over C/C++ projects. Below is an annotated example build script for a 101Java-only project with single-file fuzz targets as described above: 102 103```sh 104# Step 1: Build the project 105 106# Build the project .jar as usual, e.g. using Maven. 107mvn package 108# In this example, the project is built with Maven, which typically includes the 109# project version into the name of the packaged .jar file. The version can be 110# obtained as follows: 111CURRENT_VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \ 112-Dexpression=project.version -q -DforceStdout) 113# Copy the project .jar into $OUT under a fixed name. 114cp "target/sample-project-$CURRENT_VERSION.jar" $OUT/sample-project.jar 115 116# Specify the projects .jar file(s), separated by spaces if there are multiple. 117PROJECT_JARS="sample-project.jar" 118 119# Step 2: Build the fuzzers (should not require any changes) 120 121# The classpath at build-time includes the project jars in $OUT as well as the 122# Jazzer API. 123BUILD_CLASSPATH=$(echo $PROJECT_JARS | xargs printf -- "$OUT/%s:"):$JAZZER_API_PATH 124 125# All .jar and .class files lie in the same directory as the fuzzer at runtime. 126RUNTIME_CLASSPATH=$(echo $PROJECT_JARS | xargs printf -- "\$this_dir/%s:"):\$this_dir 127 128for fuzzer in $(find $SRC -name '*Fuzzer.java'); do 129 fuzzer_basename=$(basename -s .java $fuzzer) 130 javac -cp $BUILD_CLASSPATH $fuzzer 131 cp $SRC/$fuzzer_basename.class $OUT/ 132 133 # Create an execution wrapper that executes Jazzer with the correct arguments. 134 echo "#!/bin/sh 135# LLVMFuzzerTestOneInput for fuzzer detection. 136this_dir=\$(dirname \"\$0\") 137LD_LIBRARY_PATH=\"$JVM_LD_LIBRARY_PATH\":\$this_dir \ 138\$this_dir/jazzer_driver --agent_path=\$this_dir/jazzer_agent_deploy.jar \ 139--cp=$RUNTIME_CLASSPATH \ 140--target_class=$fuzzer_basename \ 141--jvm_args=\"-Xmx2048m;-Djava.awt.headless=true\" \ 142\$@" > $OUT/$fuzzer_basename 143 chmod +x $OUT/$fuzzer_basename 144done 145``` 146 147The [java-example](https://github.com/google/oss-fuzz/blob/master/projects/java-example/build.sh) 148project contains an example of a `build.sh` for Java projects with native 149libraries. 150 151## FuzzedDataProvider 152 153Jazzer provides a `FuzzedDataProvider` that can simplify the task of creating a 154fuzz target by translating the raw input bytes received from the fuzzer into 155useful primitive Java types. Its functionality is similar to 156`FuzzedDataProviders` available in other languages, such as 157[Python](https://github.com/google/atheris#fuzzeddataprovider) and 158[C++](https://github.com/google/fuzzing/blob/master/docs/split-inputs.md). 159 160On OSS-Fuzz, the required library is available in the base docker images under 161the path `$JAZZER_API_PATH`, which is added to the classpath by the example 162build script shown above. Locally, the library can be obtained from 163[Maven Central](https://search.maven.org/search?q=g:com.code-intelligence%20a:jazzer-api). 164 165A fuzz target using the `FuzzedDataProvider` would look as follows: 166 167```java 168import com.code_intelligence.jazzer.api.FuzzedDataProvider; 169 170public class ExampleFuzzer { 171 public static void fuzzerTestOneInput(FuzzedDataProvider data) { 172 int number = data.consumeInt(); 173 String string = data.consumeRemainingAsString(); 174 // ... 175 } 176} 177``` 178 179For a list of convenience methods offered by `FuzzedDataProvider`, consult its 180[javadocs](https://codeintelligencetesting.github.io/jazzer-api/com/code_intelligence/jazzer/api/FuzzedDataProvider.html). 181