kotlinx.fuzz
is a general purpose fuzzing library for Kotlin. The library provides basic functionality:
- Simple API for writing fuzz tests
- Gradle plugin that provides an easy way of configuring the fuzzer, running it, and generating reports
- Custom JUnit engine that handles interactions with the fuzzing engine and allows for easy integration with IDE
- Integration with Jazzer as the main fuzzing engine for now
Currently, kotlinx.fuzz
works only for JVM and requires JDK 8. Also, the library is built using Kotlin version 2.0.21, which adds additional requirements. This is a subject to change in the future.
- Add PLAN lab maven repository to your gradle config:
build.gradle.kts
:
repositories {
maven(url = "https://plan-maven.apal-research.com")
}
settings.gradle.kts
:
pluginManagement {
repositories {
maven(url = "https://plan-maven.apal-research.com")
}
}
- Add
kotlinx.fuzz
as a dependency:
dependencies {
testRuntimeOnly("org.jetbrains:kotlinx.fuzz.jazzer:0.2.0")
}
- Apply
kotlinx.fuzz
plugin to your project:
plugins {
id("kotlinx.fuzz.gradle") version "0.2.0"
}
- Configure plugin:
fuzzConfig {
instrument = listOf("org.example.**")
maxSingleTargetFuzzTime = 10.seconds
}
- Write your fuzz tests:
package org.example
import kotlinx.fuzz.KFuzzTest
import kotlinx.fuzz.KFuzzer
object ExampleTest {
@KFuzzTest
fun foo(data: KFuzzer) {
if (data.int() % 2 == 0) {
if (data.int() % 3 == 2) {
if (data.int() % 31 == 11) {
throw IllegalArgumentException()
}
}
}
}
}
- Run fuzzer:
~/example » ./gradlew fuzz 1 ↵
> Task fuzz
SampleTarget > public final void org.example.ExampleTest.foo(kotlinx.fuzz.KFuzzer) FAILED
java.lang.IllegalArgumentException
at org.example.ExampleTest.foo(ExampleTest.kt:12)
- Check the fuzzing report in
build/fuzz
You can see more examples of kotlinz.fuzz
usage in kotlinx.fuzz.test
Currently kotlinx.fuzz
can run fuzzer in two different modes:
- Fuzzing mode — in this mode
kotlinx.fuzz
will use the fuzzing engine to generate new seeds that explore the program under test, achieve the highest possible coverage and find new crashes. You can run this mode using./gradlew fuzz
command. - Regression mode — in this mode
kotlinx.fuzz
does not generate new crashes, it runs your fuzz tests on the seeds that previously triggered crashes. You can run this mode using./gradlew regression
command. If there are no previously found crashes, running this task will cause the following error:
No matching tests found in any candidate test task.
Requested tests:
Test pattern *your test name* which fails in task :regression
Both of these tasks extend built-in Gradle test
task, so you can provide additional parameters or running individual fuzz tests using the same Gradle arguments.
kotlinx.fuzz
test engine also provides integration with IDEs and allows you to run and debug your fuzz tests both in fuzz and regression mode.
kotlinx.fuzz
will generate build/fuzz
folder with the fuzzing campaign report. The general structure of the report is following:
corpus
folder contains seeds generated by fuzz engine during the fuzzing campaign.coverage
folder contains binary JaCoCo.exec
files with coverage for each individual fuzz test.jacoco-report
provides a JaCoCo coverage report in human-readable formats: HTML, CSV and XML.logs
contains fuzz engine logs for each of the fuzz tests.reproducers
folder contains crash seeds found by the fuzz engine. This folder is used bykotlinx.fuzz
duringregression
mode. Eachcrash-$hash
file is a unique crash found by the fuzz engine. Additionally, for each crash seed you can findstacktrace-$hash
file that contains a stack trace of the found crash andcluster-$hash
folder that contains all the other seeds that reproduce the same failure (you can read about in more in Crash deduplication).stats
contains fuzz engine's CSV reports for each individual fuzz test. CSV files contain information about number of executions, number of found crashes, coverage, etc.merged-coverage.exec
— JaCoCo binary file with the merged coverage of all the fuzz tests (this binary file is used to generatejacoco-report
folder).overall-stats.csv
— final CSV report of Jazzer for each of the fuzz tests.
The plugin currently allows you to configure its parameters in the fuzzConfig
section in build.gradle.kts
. Here are the main configuration options:
fuzzEngine
— fuzz engine to use, currently only"Jazzer"
is supportedinstrument
— glob patterns matching names of classes that should be instrumented for fuzzing, it determines what classes fuzzer will target during fuzzing; ideally it should be a class or a package that you want to fuzzworkDir
— directory where the all fuzzing results will be stored; default"build/fuzz"
dumpCoverage
— flag to enable/disable JaCoCo.exec
file generation, enabled by default; you can read a little bit more about logging inkotlinx.fuzz
herelogLevel
— logging level enabled forkotlinx.fuzz
;warn
by defaultmaxSingleTargetFuzzTime
— max time to fuzz a single target; default 1 minutereproducerPath
— path to store reproducers; default"$workDir/reproducers"
These and some other options can also be set through the system properties. You can check system property names here.
Design, implementation and default values of configuration properties are subject to change in the future releases.
kotlinx.fuzz
uses Jazzer as the main fuzzing engine, but also introduces several new key features:
- Improved and simplified API
- Gradle plugin that integrates all the fuzzing-related tasks into your build system
- Easy configuration
- Verification of configuration options
- Improved crash deduplication algorithm
- Improved regression mode
Trophy list can be found here