xref: /aosp_15_r20/external/jazzer-api/docs/advanced.md (revision 33edd6723662ea34453766bfdca85dbfdd5342b8)
1*33edd672SMark## Advanced options
2*33edd672SMark
3*33edd672SMark* [Passing JVM arguments](#passing-jvm-arguments)
4*33edd672SMark* [Coverage instrumentation](#coverage-instrumentation)
5*33edd672SMark* [Trace instrumentation](#trace-instrumentation)
6*33edd672SMark* [Value profile](#value-profile)
7*33edd672SMark* [Custom hooks](#custom-hooks)
8*33edd672SMark* [Suppressing stack traces](#suppressing-stack-traces)
9*33edd672SMark* [Export coverage information](#export-coverage-information)
10*33edd672SMark* [Native libraries](#native-libraries)
11*33edd672SMark* [Fuzzing mutators](#fuzzing-mutators)
12*33edd672SMark
13*33edd672SMark<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
14*33edd672SMark
15*33edd672SMarkVarious command line options are available to control the instrumentation and fuzzer execution.
16*33edd672SMarkSince Jazzer is a libFuzzer-compiled binary, all positional and single dash command-line options are parsed by libFuzzer.
17*33edd672SMarkTherefore, all Jazzer options are passed via double dash command-line flags, i.e., as `--option=value` (note the `=` instead of a space).
18*33edd672SMark
19*33edd672SMarkA full list of command-line flags can be printed with the `--help` flag.
20*33edd672SMarkFor the available libFuzzer options please refer to [its documentation](https://llvm.org/docs/LibFuzzer.html) for a detailed description.
21*33edd672SMark
22*33edd672SMark### Passing JVM arguments
23*33edd672SMark
24*33edd672SMarkWhen Jazzer is started using the `jazzer` binary, it starts a JVM in which it executes the fuzz target.
25*33edd672SMarkArguments for this JVM can be provided via the `JAVA_OPTS` environment variable.
26*33edd672SMark
27*33edd672SMarkAlternatively, arguments can also be supplied via the `--jvm_args` argument.
28*33edd672SMarkMultiple arguments are delimited by the classpath separator, which is `;` on Windows and `:` else.
29*33edd672SMarkFor example, to enable preview features as well as set a maximum heap size, add the following to the Jazzer invocation:
30*33edd672SMark
31*33edd672SMark```bash
32*33edd672SMark# Windows
33*33edd672SMark--jvm_args=--enable-preview;-Xmx1000m
34*33edd672SMark# Linux & macOS
35*33edd672SMark--jvm_args=--enable-preview:-Xmx1000m
36*33edd672SMark```
37*33edd672SMark
38*33edd672SMarkArguments specified with `--jvm_args` take precedence over those in `JAVA_OPTS`.
39*33edd672SMark
40*33edd672SMark### Coverage instrumentation
41*33edd672SMark
42*33edd672SMarkThe Jazzer agent inserts coverage markers into the JVM bytecode during class loading.
43*33edd672SMarklibFuzzer uses this information to guide its input mutations towards increased coverage.
44*33edd672SMark
45*33edd672SMarkIt is possible to restrict instrumentation to only a subset of classes with the `--instrumentation_includes` flag.
46*33edd672SMarkThis 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.
47*33edd672SMarkSimilarly, there is `--instrumentation_excludes` to exclude specific classes from instrumentation.
48*33edd672SMarkBoth flags take a list of glob patterns for the java class name separated by colon:
49*33edd672SMark
50*33edd672SMark```bash
51*33edd672SMark--instrumentation_includes=com.my_com.**:com.other_com.** --instrumentation_excludes=com.my_com.crypto.**
52*33edd672SMark```
53*33edd672SMark
54*33edd672SMarkBy 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*33edd672SMark
56*33edd672SMark### Trace instrumentation
57*33edd672SMark
58*33edd672SMarkThe agent adds additional hooks for tracing compares, integer divisions, switch statements and array indices.
59*33edd672SMarkThese hooks correspond to [clang's data flow hooks](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow).
60*33edd672SMarkThe particular instrumentation types to apply can be specified using the `--trace` flag, which accepts the following values:
61*33edd672SMark
62*33edd672SMark* `cov`: AFL-style edge coverage
63*33edd672SMark* `cmp`: compares (int, long, String) and switch cases
64*33edd672SMark* `div`: divisors in integer divisions
65*33edd672SMark* `gep`: constant array indexes
66*33edd672SMark* `indir`: call through `Method#invoke`
67*33edd672SMark* `all`: shorthand to apply all available instrumentations (except `gep`)
68*33edd672SMark
69*33edd672SMarkMultiple instrumentation types can be combined with a colon (Linux, macOS) or a semicolon (Windows).
70*33edd672SMark
71*33edd672SMark### Value profile
72*33edd672SMark
73*33edd672SMarkThe run-time flag `-use_value_profile=1` enables [libFuzzer's value profiling mode](https://llvm.org/docs/LibFuzzer.html#value-profile).
74*33edd672SMarkWhen 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.
75*33edd672SMarkSee [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*33edd672SMark
77*33edd672SMark### Custom hooks
78*33edd672SMark
79*33edd672SMarkIn order to obtain information about data passed into functions such as `String.equals` or `String.startsWith`, Jazzer hooks invocations to these methods.
80*33edd672SMarkThis 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).
81*33edd672SMarkSee [ExampleFuzzerHooks.java](../examples/src/main/java/com/example/ExampleFuzzerHooks.java) for an example of such a hook.
82*33edd672SMarkAn example for a sanitizer can be found in [ExamplePathTraversalFuzzerHooks.java](../examples/src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java).
83*33edd672SMark
84*33edd672SMarkMethod 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).
85*33edd672SMarkSee 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*33edd672SMark
87*33edd672SMarkTo 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.
88*33edd672SMarkHooks 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-).
89*33edd672SMarkThe list of custom hooks can alternatively be specified via the `Jazzer-Hook-Classes` attribute in the fuzz target JAR's manifest.
90*33edd672SMark
91*33edd672SMark### Suppressing stack traces
92*33edd672SMark
93*33edd672SMarkWith the flag `--keep_going=N` Jazzer continues fuzzing until `N` unique stack traces have been encountered.
94*33edd672SMark
95*33edd672SMarkParticular 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*33edd672SMark
97*33edd672SMark### Export coverage information
98*33edd672SMark
99*33edd672SMarkThe internally gathered JaCoCo coverage information can be exported in human-readable and JaCoCo execution data format (`.exec`).
100*33edd672SMarkThese 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*33edd672SMark
102*33edd672SMarkThe human-readable report contains coverage information, like branch and line coverage, on file level.
103*33edd672SMarkIt's useful to get a quick overview about the overall coverage. The flag `--coverage_report=<file>` can be used to generate it.
104*33edd672SMark
105*33edd672SMarkSimilar 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*33edd672SMark
107*33edd672SMarkThe JaCoCo `report` command can be used to generate reports based on this coverage dump.
108*33edd672SMarkThe JaCoCo CLI tools are available on their [GitHub release page](https://github.com/jacoco/jacoco/releases) as `zip` file.
109*33edd672SMarkThe 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).
110*33edd672SMarkFor 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`.
111*33edd672SMarkSource code to include in the report is searched for in `some/path/to/sources`.
112*33edd672SMarkAfter execution the `index.html` file in the output folder can be opened in a browser.
113*33edd672SMark```shell
114*33edd672SMarkjava -jar path/to/jacococli.jar report coverage.exec \
115*33edd672SMark  --classfiles classes.jar \
116*33edd672SMark  --sourcefiles some/path/to/sources \
117*33edd672SMark  --html report \
118*33edd672SMark  --name FuzzCoverageReport
119*33edd672SMark```
120*33edd672SMark
121*33edd672SMark### Native libraries
122*33edd672SMark
123*33edd672SMarkJazzer supports fuzzing of native libraries loaded by the JVM, for example via `System.load()`.
124*33edd672SMarkFor the fuzzer to get coverage feedback, these libraries have to be compiled with `-fsanitize=fuzzer-no-link`.
125*33edd672SMark
126*33edd672SMarkAdditional sanitizers such as AddressSanitizer or UndefinedBehaviorSanitizer are often desirable to uncover bugs inside the native libraries.
127*33edd672SMarkThe required compilation flags for native libraries are as follows:
128*33edd672SMark- *AddressSanitizer*: `-fsanitize=fuzzer-no-link,address`
129*33edd672SMark- *UndefinedBehaviorSanitizer*: `-fsanitize=fuzzer-no-link,undefined` (add `-fno-sanitize-recover=all` to crash on UBSan reports)
130*33edd672SMark
131*33edd672SMarkThen, start Jazzer with `--asan` and/or `--ubsan` to automatically preload the sanitizer runtimes.
132*33edd672SMarkJazzer defaults to using the runtimes associated with `clang` on the `PATH`.
133*33edd672SMarkIf you used a different compiler to compile the native libraries, specify it with `CC` to override this default.
134*33edd672SMarkIf 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*33edd672SMark
136*33edd672SMark**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*33edd672SMark
138*33edd672SMarkSanitizers other than AddressSanitizer and UndefinedBehaviorSanitizer are not yet supported.
139*33edd672SMarkFurthermore, due to the nature of the JVM's GC, LeakSanitizer reports too many false positives to be useful and is thus disabled.
140*33edd672SMark
141*33edd672SMarkThe fuzz targets `ExampleFuzzerWithASan` and `ExampleFuzzerWithUBSan` in the [`examples`](../examples/src/main/java/com/example) directory contain minimal working examples for fuzzing with native libraries.
142*33edd672SMarkAlso see `TurboJpegFuzzer` for a real-world example.
143*33edd672SMark
144*33edd672SMark### Fuzzing mutators
145*33edd672SMark
146*33edd672SMarkLibFuzzer API offers two functions to customize the mutation strategy which is especially useful when fuzzing functions that require structured input.
147*33edd672SMarkJazzer does not define `LLVMFuzzerCustomMutator` nor `LLVMFuzzerCustomCrossOver` and leaves the mutation strategy entirely to libFuzzer.
148*33edd672SMarkHowever, custom mutators can easily be integrated by compiling a mutator library which defines `LLVMFuzzerCustomMutator` (and optionally `LLVMFuzzerCustomCrossOver`) and pre-loading the mutator library:
149*33edd672SMark
150*33edd672SMark```bash
151*33edd672SMark# Using Bazel:
152*33edd672SMarkLD_PRELOAD=libcustom_mutator.so bazel run //:jazzer -- <arguments>
153*33edd672SMark# Using the binary release:
154*33edd672SMarkLD_PRELOAD=libcustom_mutator.so ./jazzer <arguments>
155*33edd672SMark```
156*33edd672SMark
157