xref: /aosp_15_r20/external/jazzer-api/docs/advanced.md (revision 33edd6723662ea34453766bfdca85dbfdd5342b8)
1## Advanced options
2
3* [Passing JVM arguments](#passing-jvm-arguments)
4* [Coverage instrumentation](#coverage-instrumentation)
5* [Trace instrumentation](#trace-instrumentation)
6* [Value profile](#value-profile)
7* [Custom hooks](#custom-hooks)
8* [Suppressing stack traces](#suppressing-stack-traces)
9* [Export coverage information](#export-coverage-information)
10* [Native libraries](#native-libraries)
11* [Fuzzing mutators](#fuzzing-mutators)
12
13<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
14
15Various command line options are available to control the instrumentation and fuzzer execution.
16Since Jazzer is a libFuzzer-compiled binary, all positional and single dash command-line options are parsed by libFuzzer.
17Therefore, all Jazzer options are passed via double dash command-line flags, i.e., as `--option=value` (note the `=` instead of a space).
18
19A full list of command-line flags can be printed with the `--help` flag.
20For the available libFuzzer options please refer to [its documentation](https://llvm.org/docs/LibFuzzer.html) for a detailed description.
21
22### Passing JVM arguments
23
24When Jazzer is started using the `jazzer` binary, it starts a JVM in which it executes the fuzz target.
25Arguments for this JVM can be provided via the `JAVA_OPTS` environment variable.
26
27Alternatively, arguments can also be supplied via the `--jvm_args` argument.
28Multiple arguments are delimited by the classpath separator, which is `;` on Windows and `:` else.
29For example, to enable preview features as well as set a maximum heap size, add the following to the Jazzer invocation:
30
31```bash
32# Windows
33--jvm_args=--enable-preview;-Xmx1000m
34# Linux & macOS
35--jvm_args=--enable-preview:-Xmx1000m
36```
37
38Arguments specified with `--jvm_args` take precedence over those in `JAVA_OPTS`.
39
40### Coverage instrumentation
41
42The Jazzer agent inserts coverage markers into the JVM bytecode during class loading.
43libFuzzer uses this information to guide its input mutations towards increased coverage.
44
45It is possible to restrict instrumentation to only a subset of classes with the `--instrumentation_includes` flag.
46This is especially useful if coverage inside specific packages is of higher interest, e.g., the user library under test rather than an external parsing library in which the fuzzer is likely to get lost.
47Similarly, there is `--instrumentation_excludes` to exclude specific classes from instrumentation.
48Both flags take a list of glob patterns for the java class name separated by colon:
49
50```bash
51--instrumentation_includes=com.my_com.**:com.other_com.** --instrumentation_excludes=com.my_com.crypto.**
52```
53
54By default, JVM-internal classes and Java as well as Kotlin standard library classes are not instrumented, so these do not need to be excluded manually.
55
56### Trace instrumentation
57
58The agent adds additional hooks for tracing compares, integer divisions, switch statements and array indices.
59These hooks correspond to [clang's data flow hooks](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow).
60The particular instrumentation types to apply can be specified using the `--trace` flag, which accepts the following values:
61
62* `cov`: AFL-style edge coverage
63* `cmp`: compares (int, long, String) and switch cases
64* `div`: divisors in integer divisions
65* `gep`: constant array indexes
66* `indir`: call through `Method#invoke`
67* `all`: shorthand to apply all available instrumentations (except `gep`)
68
69Multiple instrumentation types can be combined with a colon (Linux, macOS) or a semicolon (Windows).
70
71### Value profile
72
73The run-time flag `-use_value_profile=1` enables [libFuzzer's value profiling mode](https://llvm.org/docs/LibFuzzer.html#value-profile).
74When running with this flag, the feedback about compares and constants received from Jazzer's trace instrumentation is associated with the particular bytecode location and used to provide additional coverage instrumentation.
75See [ExampleValueProfileFuzzer.java](../examples/src/main/java/com/example/ExampleValueProfileFuzzer.java) for a fuzz target that would be very hard to fuzz without value profile.
76
77### Custom hooks
78
79In order to obtain information about data passed into functions such as `String.equals` or `String.startsWith`, Jazzer hooks invocations to these methods.
80This functionality is also available to fuzz targets, where it can be used to implement custom sanitizers or stub out methods that block the fuzzer from progressing (e.g. checksum verifications or random number generation).
81See [ExampleFuzzerHooks.java](../examples/src/main/java/com/example/ExampleFuzzerHooks.java) for an example of such a hook.
82An example for a sanitizer can be found in [ExamplePathTraversalFuzzerHooks.java](../examples/src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java).
83
84Method hooks can be declared using the `@MethodHook` annotation defined in the `com.code_intelligence.jazzer.api` package, which is contained in `jazzer_standalone.jar` (binary release) or in the Maven artifact [`com.code-intelligence:jazzer-api`](https://search.maven.org/search?q=g:com.code-intelligence%20a:jazzer-api).
85See the [javadocs of the `@MethodHook` API](https://codeintelligencetesting.github.io/jazzer-docs/jazzer-api/com/code_intelligence/jazzer/api/MethodHook.html) for more details.
86
87To use the compiled method hooks, they have to be available on the classpath provided by `--cp` and can then be loaded by providing the flag `--custom_hooks`, which takes a colon-separated list of names of classes to load hooks from.
88Hooks have to be loaded from separate JAR files so that Jazzer can [add it to the bootstrap class loader search](https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html#appendToBootstrapClassLoaderSearch-java.util.jar.JarFile-).
89The list of custom hooks can alternatively be specified via the `Jazzer-Hook-Classes` attribute in the fuzz target JAR's manifest.
90
91### Suppressing stack traces
92
93With the flag `--keep_going=N` Jazzer continues fuzzing until `N` unique stack traces have been encountered.
94
95Particular stack traces can also be ignored based on their `DEDUP_TOKEN` by passing a comma-separated list of tokens via `--ignore=<token_1>,<token2>`.
96
97### Export coverage information
98
99The internally gathered JaCoCo coverage information can be exported in human-readable and JaCoCo execution data format (`.exec`).
100These can help identify code areas that have not been covered by the fuzzer and thus may require more comprehensive fuzz targets or a more extensive initial corpus to reach.
101
102The human-readable report contains coverage information, like branch and line coverage, on file level.
103It's useful to get a quick overview about the overall coverage. The flag `--coverage_report=<file>` can be used to generate it.
104
105Similar to the JaCoCo `dump` command, the flag `--coverage_dump=<file>` specifies a coverage dump file, often called `jacoco.exec`, that is generated after the fuzzing run. It contains a binary representation of the gathered coverage data in the JaCoCo format.
106
107The JaCoCo `report` command can be used to generate reports based on this coverage dump.
108The JaCoCo CLI tools are available on their [GitHub release page](https://github.com/jacoco/jacoco/releases) as `zip` file.
109The report tool is located in the `lib` folder and can be used as described in the JaCoCo [CLI documentation](https://www.eclemma.org/jacoco/trunk/doc/cli.html).
110For example the following command generates an HTML report in the folder `report` containing all classes available in `classes.jar` and their coverage as captured in the export `coverage.exec`.
111Source code to include in the report is searched for in `some/path/to/sources`.
112After execution the `index.html` file in the output folder can be opened in a browser.
113```shell
114java -jar path/to/jacococli.jar report coverage.exec \
115  --classfiles classes.jar \
116  --sourcefiles some/path/to/sources \
117  --html report \
118  --name FuzzCoverageReport
119```
120
121### Native libraries
122
123Jazzer supports fuzzing of native libraries loaded by the JVM, for example via `System.load()`.
124For the fuzzer to get coverage feedback, these libraries have to be compiled with `-fsanitize=fuzzer-no-link`.
125
126Additional sanitizers such as AddressSanitizer or UndefinedBehaviorSanitizer are often desirable to uncover bugs inside the native libraries.
127The required compilation flags for native libraries are as follows:
128- *AddressSanitizer*: `-fsanitize=fuzzer-no-link,address`
129- *UndefinedBehaviorSanitizer*: `-fsanitize=fuzzer-no-link,undefined` (add `-fno-sanitize-recover=all` to crash on UBSan reports)
130
131Then, start Jazzer with `--asan` and/or `--ubsan` to automatically preload the sanitizer runtimes.
132Jazzer defaults to using the runtimes associated with `clang` on the `PATH`.
133If you used a different compiler to compile the native libraries, specify it with `CC` to override this default.
134If no compiler is available in your runtime environment (e.g. in OSS-Fuzz) but you have a directory that contains the required sanitier libraries, specify its path in `JAZZER_NATIVE_SANITIZERS_DIR`.
135
136**Note:** On macOS, you may see Gatekeeper warnings when using `--asan` and/or `--ubsan` since these flags cause the native sanitizer libraries to be preloaded into the codesigned `java` executable via `DYLD_INSERT_LIBRARIES`.
137
138Sanitizers other than AddressSanitizer and UndefinedBehaviorSanitizer are not yet supported.
139Furthermore, due to the nature of the JVM's GC, LeakSanitizer reports too many false positives to be useful and is thus disabled.
140
141The fuzz targets `ExampleFuzzerWithASan` and `ExampleFuzzerWithUBSan` in the [`examples`](../examples/src/main/java/com/example) directory contain minimal working examples for fuzzing with native libraries.
142Also see `TurboJpegFuzzer` for a real-world example.
143
144### Fuzzing mutators
145
146LibFuzzer API offers two functions to customize the mutation strategy which is especially useful when fuzzing functions that require structured input.
147Jazzer does not define `LLVMFuzzerCustomMutator` nor `LLVMFuzzerCustomCrossOver` and leaves the mutation strategy entirely to libFuzzer.
148However, custom mutators can easily be integrated by compiling a mutator library which defines `LLVMFuzzerCustomMutator` (and optionally `LLVMFuzzerCustomCrossOver`) and pre-loading the mutator library:
149
150```bash
151# Using Bazel:
152LD_PRELOAD=libcustom_mutator.so bazel run //:jazzer -- <arguments>
153# Using the binary release:
154LD_PRELOAD=libcustom_mutator.so ./jazzer <arguments>
155```
156
157