aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/BUILD.bazel321
-rwxr-xr-xexamples/check_for_finding.sh41
-rw-r--r--examples/json_sanitizer_denylist_crashbin0 -> 38 bytes
-rw-r--r--examples/src/main/java/com/example/ExampleFuzzer.java40
-rw-r--r--examples/src/main/java/com/example/ExampleFuzzerHooks.java30
-rw-r--r--examples/src/main/java/com/example/ExampleFuzzerWithNative.java36
-rw-r--r--examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java28
-rw-r--r--examples/src/main/java/com/example/ExamplePathTraversalFuzzer.java43
-rw-r--r--examples/src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java46
-rw-r--r--examples/src/main/java/com/example/ExampleStackOverflowFuzzer.java33
-rw-r--r--examples/src/main/java/com/example/ExampleValueProfileFuzzer.java53
-rw-r--r--examples/src/main/java/com/example/FastJsonFuzzer.java30
-rw-r--r--examples/src/main/java/com/example/GifImageParserFuzzer.java32
-rw-r--r--examples/src/main/java/com/example/JacksonCborFuzzer.java34
-rw-r--r--examples/src/main/java/com/example/JpegImageParserFuzzer.java45
-rw-r--r--examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java30
-rw-r--r--examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java45
-rw-r--r--examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java34
-rw-r--r--examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java42
-rw-r--r--examples/src/main/java/com/example/KlaxonFuzzer.kt31
-rw-r--r--examples/src/main/java/com/example/Log4jFuzzer.java82
-rw-r--r--examples/src/main/java/com/example/TiffImageParserFuzzer.java31
-rw-r--r--examples/src/main/java/com/example/TurboJpegFuzzer.java59
-rw-r--r--examples/src/main/native/com/example/BUILD.bazel49
-rw-r--r--examples/src/main/native/com/example/com_example_ExampleFuzzerWithNative.cpp42
25 files changed, 1257 insertions, 0 deletions
diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel
new file mode 100644
index 00000000..dde8aaeb
--- /dev/null
+++ b/examples/BUILD.bazel
@@ -0,0 +1,321 @@
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@fmeum_rules_jni//jni:defs.bzl", "java_jni_library")
+load("//bazel:compat.bzl", "SKIP_ON_MACOS", "SKIP_ON_WINDOWS")
+load("//bazel:fuzz_target.bzl", "java_fuzz_target_test")
+
+java_fuzz_target_test(
+ name = "Autofuzz",
+ fuzzer_args = [
+ "--autofuzz=com.google.json.JsonSanitizer::sanitize",
+ # Exit after the first finding for testing purposes.
+ "--keep_going=1",
+ ],
+ runtime_deps = [
+ "@maven//:com_mikesamuel_json_sanitizer",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "ExampleFuzzer",
+ srcs = [
+ "src/main/java/com/example/ExampleFuzzer.java",
+ "src/main/java/com/example/ExampleFuzzerHooks.java",
+ ],
+ # Comment out the next line to keep the fuzzer running indefinitely.
+ hook_classes = ["com.example.ExampleFuzzerHooks"],
+ target_class = "com.example.ExampleFuzzer",
+)
+
+java_jni_library(
+ name = "example_fuzzer_with_native_lib",
+ srcs = [
+ "src/main/java/com/example/ExampleFuzzerWithNative.java",
+ ],
+ native_libs = [
+ "//examples/src/main/native/com/example:native_asan",
+ "//examples/src/main/native/com/example:native_ubsan",
+ ],
+ visibility = ["//examples/src/main/native/com/example:__pkg__"],
+ deps = [
+ "//agent:jazzer_api_compile_only",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "ExampleFuzzerWithASan",
+ fuzzer_args = ["--jvm_args=-Djazzer.native_lib=native_asan"],
+ sanitizer = "address",
+ target_class = "com.example.ExampleFuzzerWithNative",
+ runtime_deps = [
+ ":example_fuzzer_with_native_lib",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "ExampleFuzzerWithUBSan",
+ fuzzer_args = ["--jvm_args=-Djazzer.native_lib=native_ubsan"],
+ sanitizer = "undefined",
+ target_class = "com.example.ExampleFuzzerWithNative",
+ # Crashes at runtime without an error message.
+ target_compatible_with = SKIP_ON_WINDOWS,
+ runtime_deps = [
+ ":example_fuzzer_with_native_lib",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "ExamplePathTraversalFuzzer",
+ srcs = [
+ "src/main/java/com/example/ExamplePathTraversalFuzzer.java",
+ "src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java",
+ ],
+ hook_classes = ["com.example.ExamplePathTraversalFuzzerHooks"],
+ target_class = "com.example.ExamplePathTraversalFuzzer",
+)
+
+java_fuzz_target_test(
+ name = "ExampleValueProfileFuzzer",
+ srcs = [
+ "src/main/java/com/example/ExampleValueProfileFuzzer.java",
+ ],
+ # Comment out the next line to keep the fuzzer running indefinitely.
+ fuzzer_args = ["-use_value_profile=1"],
+ target_class = "com.example.ExampleValueProfileFuzzer",
+)
+
+java_fuzz_target_test(
+ name = "ExampleOutOfMemoryFuzzer",
+ srcs = [
+ "src/main/java/com/example/ExampleOutOfMemoryFuzzer.java",
+ ],
+ fuzzer_args = ["--jvm_args=-Xmx512m"],
+ target_class = "com.example.ExampleOutOfMemoryFuzzer",
+)
+
+java_fuzz_target_test(
+ name = "ExampleStackOverflowFuzzer",
+ srcs = [
+ "src/main/java/com/example/ExampleStackOverflowFuzzer.java",
+ ],
+ target_class = "com.example.ExampleStackOverflowFuzzer",
+ # Crashes with a segfault before any stack trace printing is reached.
+ target_compatible_with = SKIP_ON_MACOS,
+)
+
+# WARNING: This fuzz target uses a vulnerable version of log4j, which could result in the execution
+# of arbitrary code during fuzzing if executed with an older JDK. Use at your own risk.
+java_fuzz_target_test(
+ name = "Log4jFuzzer",
+ timeout = "long",
+ srcs = [
+ "src/main/java/com/example/Log4jFuzzer.java",
+ ],
+ fuzzer_args = [
+ "-fork=4",
+ "-use_value_profile=1",
+ ],
+ # Finding this bug takes ~5 minutes on a decent laptop, but the GitHub Actions machines are not
+ # powerful enough to run it as part of our test suite.
+ tags = ["manual"],
+ target_class = "com.example.Log4jFuzzer",
+ deps = [
+ "@maven//:org_apache_logging_log4j_log4j_api",
+ "@maven//:org_apache_logging_log4j_log4j_core",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "JpegImageParserFuzzer",
+ srcs = [
+ "src/main/java/com/example/JpegImageParserFuzzer.java",
+ ],
+ fuzzer_args = [
+ "-fork=5",
+ "--additional_jvm_args=-Dbaz=baz",
+ ] + select({
+ # \\\\ becomes \\ when evaluated as a Starlark string literal, then \ in
+ # java_fuzz_target_test.
+ "@platforms//os:windows": ["--jvm_args=-Dfoo=foo;-Dbar=b\\\\;ar"],
+ "//conditions:default": ["--jvm_args=-Dfoo=foo:-Dbar=b\\\\:ar"],
+ }),
+ target_class = "com.example.JpegImageParserFuzzer",
+ # The exit codes of the forked libFuzzer processes are not picked up correctly.
+ target_compatible_with = SKIP_ON_MACOS,
+ deps = [
+ "@maven//:org_apache_commons_commons_imaging",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "GifImageParserFuzzer",
+ srcs = [
+ "src/main/java/com/example/GifImageParserFuzzer.java",
+ ],
+ target_class = "com.example.GifImageParserFuzzer",
+ deps = [
+ "@maven//:org_apache_commons_commons_imaging",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "TiffImageParserFuzzer",
+ srcs = [
+ "src/main/java/com/example/TiffImageParserFuzzer.java",
+ ],
+ tags = ["manual"],
+ target_class = "com.example.TiffImageParserFuzzer",
+ deps = [
+ "@maven//:org_apache_commons_commons_imaging",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "JsonSanitizerCrashFuzzer",
+ srcs = [
+ "src/main/java/com/example/JsonSanitizerCrashFuzzer.java",
+ ],
+ target_class = "com.example.JsonSanitizerCrashFuzzer",
+ deps = [
+ "@maven//:com_mikesamuel_json_sanitizer",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "JsonSanitizerDenylistFuzzer",
+ srcs = [
+ "src/main/java/com/example/JsonSanitizerDenylistFuzzer.java",
+ ],
+ target_class = "com.example.JsonSanitizerDenylistFuzzer",
+ deps = [
+ "@maven//:com_mikesamuel_json_sanitizer",
+ ],
+)
+
+java_binary(
+ name = "JsonSanitizerReplayerCrash",
+ data = [
+ ":json_sanitizer_denylist_crash",
+ ],
+ main_class = "com.code_intelligence.jazzer.replay.Replayer",
+ runtime_deps = [
+ ":JsonSanitizerDenylistFuzzer_target_deploy.jar",
+ "//agent/src/main/java/com/code_intelligence/jazzer/replay:Replayer_deploy.jar",
+ ],
+)
+
+sh_test(
+ name = "JsonSanitizerReplayerCrashTest",
+ srcs = ["check_for_finding.sh"],
+ args = [
+ "jazzer/$(rootpath :JsonSanitizerReplayerCrash)",
+ "com.example.JsonSanitizerDenylistFuzzer",
+ "jazzer/$(rootpath :json_sanitizer_denylist_crash)",
+ ],
+ data = [
+ ":JsonSanitizerReplayerCrash",
+ ":json_sanitizer_denylist_crash",
+ ],
+ deps = [
+ "@bazel_tools//tools/bash/runfiles",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "JsonSanitizerIdempotenceFuzzer",
+ srcs = [
+ "src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java",
+ ],
+ target_class = "com.example.JsonSanitizerIdempotenceFuzzer",
+ deps = [
+ "@maven//:com_mikesamuel_json_sanitizer",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "JsonSanitizerValidJsonFuzzer",
+ srcs = [
+ "src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java",
+ ],
+ target_class = "com.example.JsonSanitizerValidJsonFuzzer",
+ deps = [
+ "@maven//:com_google_code_gson_gson",
+ "@maven//:com_mikesamuel_json_sanitizer",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "JacksonCborFuzzer",
+ srcs = [
+ "src/main/java/com/example/JacksonCborFuzzer.java",
+ ],
+ target_class = "com.example.JacksonCborFuzzer",
+ deps = [
+ "@maven//:com_fasterxml_jackson_core_jackson_core",
+ "@maven//:com_fasterxml_jackson_core_jackson_databind",
+ "@maven//:com_fasterxml_jackson_dataformat_jackson_dataformat_cbor",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "FastJsonFuzzer",
+ srcs = [
+ "src/main/java/com/example/FastJsonFuzzer.java",
+ ],
+ target_class = "com.example.FastJsonFuzzer",
+ deps = [
+ "@maven//:com_alibaba_fastjson",
+ ],
+)
+
+kt_jvm_library(
+ name = "KlaxonFuzzTarget",
+ srcs = [
+ "src/main/java/com/example/KlaxonFuzzer.kt",
+ ],
+ deps = [
+ "//agent:jazzer_api_compile_only",
+ "@maven//:com_beust_klaxon",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "KlaxonFuzzer",
+ fuzzer_args = [
+ "--keep_going=7",
+ ],
+ target_class = "com.example.KlaxonFuzzer",
+ runtime_deps = [":KlaxonFuzzTarget"],
+)
+
+java_fuzz_target_test(
+ name = "TurboJpegFuzzer",
+ srcs = [
+ "src/main/java/com/example/TurboJpegFuzzer.java",
+ ],
+ fuzzer_args = [
+ "-rss_limit_mb=8196",
+ ],
+ native_libs = [
+ "@libjpeg_turbo//:turbojpeg_native",
+ ],
+ sanitizer = "address",
+ tags = ["manual"],
+ target_class = "com.example.TurboJpegFuzzer",
+ deps = [
+ "@libjpeg_turbo//:turbojpeg_java",
+ ],
+)
+
+java_binary(
+ name = "examples",
+ create_executable = False,
+ visibility = ["//visibility:public"],
+ runtime_deps = [
+ ":ExampleFuzzer_target_deploy.jar",
+ ":ExampleValueProfileFuzzer_target_deploy.jar",
+ ":FastJsonFuzzer_target_deploy.jar",
+ ":JacksonCborFuzzer_target_deploy.jar",
+ ":JpegImageParserFuzzer_target_deploy.jar",
+ ":JsonSanitizerDenylistFuzzer_target_deploy.jar",
+ ],
+)
diff --git a/examples/check_for_finding.sh b/examples/check_for_finding.sh
new file mode 100755
index 00000000..afe110c6
--- /dev/null
+++ b/examples/check_for_finding.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+# Copyright 2021 Code Intelligence GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# --- begin runfiles.bash initialization v2 ---
+# Copy-pasted from the Bazel Bash runfiles library v2.
+set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
+source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$0.runfiles/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
+# --- end runfiles.bash initialization v2 ---
+
+# Temporarily disable exit on error since we expect the command below to fail.
+set +e
+"$(rlocation "$1")" "$2" "$(rlocation "$3")" "${@:4}"
+declare -i exit_code=$?
+set -e
+
+# Assert that we either found a crash in java (exit code 77) or an ASan crash
+# (exit code 76).
+if [ $exit_code -eq 77 ] || [ $exit_code -eq 76 ]
+then
+ exit 0
+else
+ echo "Unexpected exit code: $exit_code"
+ exit 1
+fi
diff --git a/examples/json_sanitizer_denylist_crash b/examples/json_sanitizer_denylist_crash
new file mode 100644
index 00000000..7324203a
--- /dev/null
+++ b/examples/json_sanitizer_denylist_crash
Binary files differ
diff --git a/examples/src/main/java/com/example/ExampleFuzzer.java b/examples/src/main/java/com/example/ExampleFuzzer.java
new file mode 100644
index 00000000..073d924a
--- /dev/null
+++ b/examples/src/main/java/com/example/ExampleFuzzer.java
@@ -0,0 +1,40 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium;
+import java.security.SecureRandom;
+
+public class ExampleFuzzer {
+ public static void fuzzerInitialize() {
+ // Optional initialization to be run before the first call to fuzzerTestOneInput.
+ }
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ String input = data.consumeRemainingAsString();
+ // Without the hook in ExampleFuzzerHooks.java, the value of random would change on every
+ // invocation, making it almost impossible to guess for the fuzzer.
+ long random = new SecureRandom().nextLong();
+ if (input.startsWith("magicstring" + random) && input.length() > 30
+ && input.charAt(25) == 'C') {
+ mustNeverBeCalled();
+ }
+ }
+
+ private static void mustNeverBeCalled() {
+ throw new FuzzerSecurityIssueMedium("mustNeverBeCalled has been called");
+ }
+}
diff --git a/examples/src/main/java/com/example/ExampleFuzzerHooks.java b/examples/src/main/java/com/example/ExampleFuzzerHooks.java
new file mode 100644
index 00000000..41f16635
--- /dev/null
+++ b/examples/src/main/java/com/example/ExampleFuzzerHooks.java
@@ -0,0 +1,30 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.HookType;
+import com.code_intelligence.jazzer.api.MethodHook;
+import java.lang.invoke.MethodHandle;
+
+public class ExampleFuzzerHooks {
+ @MethodHook(type = HookType.REPLACE, targetClassName = "java.security.SecureRandom",
+ targetMethod = "nextLong", targetMethodDescriptor = "()J")
+ public static long
+ getRandomNumber(MethodHandle handle, Object thisObject, Object[] args, int hookId) {
+ return 4; // chosen by fair dice roll.
+ // guaranteed to be random.
+ // https://xkcd.com/221/
+ }
+}
diff --git a/examples/src/main/java/com/example/ExampleFuzzerWithNative.java b/examples/src/main/java/com/example/ExampleFuzzerWithNative.java
new file mode 100644
index 00000000..b9a13e24
--- /dev/null
+++ b/examples/src/main/java/com/example/ExampleFuzzerWithNative.java
@@ -0,0 +1,36 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.github.fmeum.rules_jni.RulesJni;
+
+public class ExampleFuzzerWithNative {
+ static {
+ String native_lib = System.getProperty("jazzer.native_lib");
+ RulesJni.loadLibrary(native_lib, ExampleFuzzerWithNative.class);
+ }
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ int val = data.consumeInt();
+ String stringData = data.consumeRemainingAsString();
+ if (val == 17759716 && stringData.length() > 10 && stringData.contains("jazzer")) {
+ // call native function which contains a crash
+ new ExampleFuzzerWithNative().parse(stringData);
+ }
+ }
+
+ private native boolean parse(String bytes);
+} \ No newline at end of file
diff --git a/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java b/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java
new file mode 100644
index 00000000..d704da39
--- /dev/null
+++ b/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java
@@ -0,0 +1,28 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import java.util.ArrayList;
+
+public class ExampleOutOfMemoryFuzzer {
+ public static void fuzzerTestOneInput(byte[] input) {
+ ArrayList<Byte> bytes = new ArrayList<>();
+ int pos = 0;
+ while (pos >= 0 && pos < input.length) {
+ bytes.add(input[pos]);
+ pos += input[pos] + 1;
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/ExamplePathTraversalFuzzer.java b/examples/src/main/java/com/example/ExamplePathTraversalFuzzer.java
new file mode 100644
index 00000000..f53ccb3c
--- /dev/null
+++ b/examples/src/main/java/com/example/ExamplePathTraversalFuzzer.java
@@ -0,0 +1,43 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import java.io.File;
+import java.io.IOException;
+
+public class ExamplePathTraversalFuzzer {
+ /**
+ * The root path for all files that this application is allowed to upload.
+ */
+ public static final String publicFilesRootPath = "/app/upload/";
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ String relativePath = data.consumeRemainingAsAsciiString();
+ // Upload the file and try very hard to ignore errors thrown during the upload.
+ try {
+ uploadFile(relativePath);
+ } catch (Throwable ignored) {
+ }
+ }
+
+ private static void uploadFile(String relativePathToFile) throws IOException {
+ File fileToUpload = new File(publicFilesRootPath + relativePathToFile);
+ if (!fileToUpload.exists()) {
+ throw new IOException("File not found");
+ }
+ // In a real application, the file would be uploaded to a public server here.
+ }
+}
diff --git a/examples/src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java b/examples/src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java
new file mode 100644
index 00000000..b027de5b
--- /dev/null
+++ b/examples/src/main/java/com/example/ExamplePathTraversalFuzzerHooks.java
@@ -0,0 +1,46 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh;
+import com.code_intelligence.jazzer.api.HookType;
+import com.code_intelligence.jazzer.api.Jazzer;
+import com.code_intelligence.jazzer.api.MethodHook;
+import java.lang.invoke.MethodHandle;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class ExamplePathTraversalFuzzerHooks {
+ @MethodHook(type = HookType.BEFORE, targetClassName = "java.io.File", targetMethod = "<init>",
+ targetMethodDescriptor = "(Ljava/lang/String;)V")
+ public static void
+ fileConstructorHook(MethodHandle handle, Object thisObject, Object[] args, int hookId) {
+ String path = (String) args[0];
+ Path normalizedPath;
+ try {
+ normalizedPath = Paths.get(path).normalize();
+ } catch (InvalidPathException e) {
+ // Invalid paths are correctly rejected by the application.
+ return;
+ }
+ if (!normalizedPath.startsWith(ExamplePathTraversalFuzzer.publicFilesRootPath)) {
+ // Simply throwing an exception from here would not work as the calling code catches and
+ // ignores all Throwables. Instead, use the Jazzer API to report a finding from a hook.
+ Jazzer.reportFindingFromHook(new FuzzerSecurityIssueHigh(
+ "Path traversal discovered: '" + path + "' --> '" + normalizedPath + "'"));
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/ExampleStackOverflowFuzzer.java b/examples/src/main/java/com/example/ExampleStackOverflowFuzzer.java
new file mode 100644
index 00000000..47166af4
--- /dev/null
+++ b/examples/src/main/java/com/example/ExampleStackOverflowFuzzer.java
@@ -0,0 +1,33 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import java.math.BigDecimal;
+
+public class ExampleStackOverflowFuzzer {
+ public static void fuzzerTestOneInput(byte[] input) {
+ step1();
+ }
+
+ private static void step1() {
+ BigDecimal unused = BigDecimal.valueOf(10, 100);
+ step2();
+ }
+
+ private static void step2() {
+ boolean unused = "foobar".contains("bar");
+ step1();
+ }
+}
diff --git a/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java b/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java
new file mode 100644
index 00000000..acc023a2
--- /dev/null
+++ b/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java
@@ -0,0 +1,53 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow;
+import java.util.Base64;
+
+public class ExampleValueProfileFuzzer {
+ private static String base64(byte[] input) {
+ return Base64.getEncoder().encodeToString(input);
+ }
+
+ private static long insecureEncrypt(long input) {
+ long key = 0xefe4eb93215cb6b0L;
+ return input ^ key;
+ }
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ // Without -use_value_profile=1, the fuzzer gets stuck here as there is no direct correspondence
+ // between the input bytes and the compared string. With value profile, the fuzzer can guess the
+ // expected input byte by byte, which takes linear rather than exponential time.
+ if (base64(data.consumeBytes(6)).equals("SmF6emVy")) {
+ long[] plaintextBlocks = data.consumeLongs(2);
+ if (plaintextBlocks.length != 2)
+ return;
+ if (insecureEncrypt(plaintextBlocks[0]) == 0x9fc48ee64d3dc090L) {
+ // Without --fake_pcs (enabled by default with -use_value_profile=1), the fuzzer would get
+ // stuck here as the value profile information for long comparisons would not be able to
+ // distinguish between this comparison and the one above.
+ if (insecureEncrypt(plaintextBlocks[1]) == 0x888a82ff483ad9c2L) {
+ mustNeverBeCalled();
+ }
+ }
+ }
+ }
+
+ private static void mustNeverBeCalled() {
+ throw new FuzzerSecurityIssueLow("mustNeverBeCalled has been called");
+ }
+}
diff --git a/examples/src/main/java/com/example/FastJsonFuzzer.java b/examples/src/main/java/com/example/FastJsonFuzzer.java
new file mode 100644
index 00000000..2e5d4797
--- /dev/null
+++ b/examples/src/main/java/com/example/FastJsonFuzzer.java
@@ -0,0 +1,30 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+
+// Found the issues described in
+// https://github.com/alibaba/fastjson/issues/3631
+public class FastJsonFuzzer {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ try {
+ JSON.parse(data.consumeRemainingAsString());
+ } catch (JSONException ignored) {
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/GifImageParserFuzzer.java b/examples/src/main/java/com/example/GifImageParserFuzzer.java
new file mode 100644
index 00000000..ab7de907
--- /dev/null
+++ b/examples/src/main/java/com/example/GifImageParserFuzzer.java
@@ -0,0 +1,32 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import java.io.IOException;
+import java.util.HashMap;
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
+import org.apache.commons.imaging.formats.gif.GifImageParser;
+
+// Found https://issues.apache.org/jira/browse/IMAGING-277 and
+// https://issues.apache.org/jira/browse/IMAGING-278.
+public class GifImageParserFuzzer {
+ public static void fuzzerTestOneInput(byte[] input) {
+ try {
+ new GifImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>());
+ } catch (IOException | ImageReadException ignored) {
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/JacksonCborFuzzer.java b/examples/src/main/java/com/example/JacksonCborFuzzer.java
new file mode 100644
index 00000000..902c1d96
--- /dev/null
+++ b/examples/src/main/java/com/example/JacksonCborFuzzer.java
@@ -0,0 +1,34 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
+import java.io.IOException;
+
+// Reproduces https://github.com/FasterXML/jackson-dataformats-binary/issues/236 and
+// https://github.com/FasterXML/jackson-databind/pull/3032 if executed with
+// `--keep_going=3 -seed=2735196724`.
+public class JacksonCborFuzzer {
+ public static void fuzzerTestOneInput(byte[] input) {
+ CBORFactory factory = new CBORFactory();
+ ObjectMapper mapper = new ObjectMapper(factory);
+ mapper.enableDefaultTyping();
+ try {
+ mapper.readTree(input);
+ } catch (IOException ignored) {
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/JpegImageParserFuzzer.java b/examples/src/main/java/com/example/JpegImageParserFuzzer.java
new file mode 100644
index 00000000..a6898bf0
--- /dev/null
+++ b/examples/src/main/java/com/example/JpegImageParserFuzzer.java
@@ -0,0 +1,45 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import java.io.IOException;
+import java.util.HashMap;
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
+import org.apache.commons.imaging.formats.jpeg.JpegImageParser;
+
+// Found https://issues.apache.org/jira/browse/IMAGING-275.
+public class JpegImageParserFuzzer {
+ public static void fuzzerInitialize() {
+ String foo = System.getProperty("foo");
+ String bar = System.getProperty("bar");
+ String baz = System.getProperty("baz");
+ // Only used to verify that arguments are correctly passed down to child processes.
+ if (foo == null || bar == null || baz == null || !foo.equals("foo")
+ || !(bar.equals("b;ar") || bar.equals("b:ar")) || !baz.equals("baz")) {
+ // Exit the process with an exit code different from that for a finding.
+ System.err.println("ERROR: Did not correctly pass all jvm_args to child process.");
+ System.err.printf("foo: %s%nbar: %s%nbaz: %s%n", foo, bar, baz);
+ System.exit(3);
+ }
+ }
+
+ public static void fuzzerTestOneInput(byte[] input) {
+ try {
+ new JpegImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>());
+ } catch (IOException | ImageReadException ignored) {
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java
new file mode 100644
index 00000000..05ac4611
--- /dev/null
+++ b/examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java
@@ -0,0 +1,30 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.google.json.JsonSanitizer;
+
+public class JsonSanitizerCrashFuzzer {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ String input = data.consumeRemainingAsString();
+ try {
+ JsonSanitizer.sanitize(input, 10);
+ } catch (ArrayIndexOutOfBoundsException ignored) {
+ // ArrayIndexOutOfBoundsException is expected if nesting depth is
+ // exceeded.
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java
new file mode 100644
index 00000000..e715b1d9
--- /dev/null
+++ b/examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java
@@ -0,0 +1,45 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh;
+import com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium;
+import com.google.json.JsonSanitizer;
+
+public class JsonSanitizerDenylistFuzzer {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ String input = data.consumeRemainingAsString();
+ String validJson;
+ try {
+ validJson = JsonSanitizer.sanitize(input, 10);
+ } catch (Exception e) {
+ return;
+ }
+
+ // Check for forbidden substrings. As these would enable Cross-Site Scripting, treat every
+ // finding as a high severity vulnerability.
+ assert !validJson.contains("</script")
+ : new FuzzerSecurityIssueHigh("Output contains </script");
+ assert !validJson.contains("]]>") : new FuzzerSecurityIssueHigh("Output contains ]]>");
+
+ // Check for more forbidden substrings. As these would not directly enable Cross-Site Scripting
+ // in general, but may impact script execution on the embedding page, treat each finding as a
+ // medium severity vulnerability.
+ assert !validJson.contains("<script")
+ : new FuzzerSecurityIssueMedium("Output contains <script");
+ assert !validJson.contains("<!--") : new FuzzerSecurityIssueMedium("Output contains <!--");
+ }
+}
diff --git a/examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java
new file mode 100644
index 00000000..111d3de2
--- /dev/null
+++ b/examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java
@@ -0,0 +1,34 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.google.json.JsonSanitizer;
+
+public class JsonSanitizerIdempotenceFuzzer {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ String input = data.consumeRemainingAsString();
+ String validJson;
+ try {
+ validJson = JsonSanitizer.sanitize(input, 10);
+ } catch (Exception e) {
+ return;
+ }
+
+ // Ensure that sanitizing twice does not give different output (idempotence). Since failure to
+ // be idempotent is not a security issue in itself, fail with a regular AssertionError.
+ assert JsonSanitizer.sanitize(validJson).equals(validJson) : "Not idempotent";
+ }
+}
diff --git a/examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java
new file mode 100644
index 00000000..2d270966
--- /dev/null
+++ b/examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java
@@ -0,0 +1,42 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.json.JsonSanitizer;
+
+public class JsonSanitizerValidJsonFuzzer {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ String input = data.consumeRemainingAsString();
+ String validJson;
+ try {
+ validJson = JsonSanitizer.sanitize(input, 10);
+ } catch (Exception e) {
+ return;
+ }
+
+ // Check that the output is valid JSON. Invalid JSON may crash other parts of the application
+ // that trust the output of the sanitizer.
+ try {
+ Gson gson = new Gson();
+ gson.fromJson(validJson, JsonElement.class);
+ } catch (Exception e) {
+ throw new FuzzerSecurityIssueLow("Output is invalid JSON", e);
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/KlaxonFuzzer.kt b/examples/src/main/java/com/example/KlaxonFuzzer.kt
new file mode 100644
index 00000000..39216eea
--- /dev/null
+++ b/examples/src/main/java/com/example/KlaxonFuzzer.kt
@@ -0,0 +1,31 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example
+
+import com.beust.klaxon.KlaxonException
+import com.beust.klaxon.Parser
+import com.code_intelligence.jazzer.api.FuzzedDataProvider
+
+// Reproduces https://github.com/cbeust/klaxon/pull/330
+object KlaxonFuzzer {
+
+ @JvmStatic
+ fun fuzzerTestOneInput(data: FuzzedDataProvider) {
+ try {
+ Parser.default().parse(StringBuilder(data.consumeRemainingAsString()))
+ } catch (_: KlaxonException) {
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/Log4jFuzzer.java b/examples/src/main/java/com/example/Log4jFuzzer.java
new file mode 100644
index 00000000..41870c9c
--- /dev/null
+++ b/examples/src/main/java/com/example/Log4jFuzzer.java
@@ -0,0 +1,82 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+
+// This fuzzer reproduces the log4j RCE vulnerability CVE-2021-44228.
+public class Log4jFuzzer {
+ private final static Logger log = LogManager.getLogger(Log4jFuzzer.class.getName());
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ log.error(data.consumeRemainingAsString());
+ }
+
+ public static void fuzzerInitialize() {
+ // Install a logger that constructs the log message, but never prints it.
+ // This noticeably increases the fuzzing performance
+ DefaultConfigurationBuilder configBuilder = new DefaultConfigurationBuilder();
+ configBuilder.setPackages(FuzzingAppender.class.getPackage().getName());
+ AppenderComponentBuilder fuzzingAppender =
+ configBuilder.newAppender("nullAppender", "FuzzingAppender");
+ configBuilder.add(fuzzingAppender);
+ RootLoggerComponentBuilder rootLogger = configBuilder.newRootLogger();
+ rootLogger.add(configBuilder.newAppenderRef("nullAppender"));
+ configBuilder.add(rootLogger);
+ Configurator.reconfigure(configBuilder.build());
+
+ // Disable logging of exceptions caught in log4j itself.
+ StatusLogger.getLogger().reset();
+ StatusLogger.getLogger().setLevel(Level.OFF);
+ }
+
+ @Plugin(
+ name = "FuzzingAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
+ public static class FuzzingAppender extends AbstractAppender {
+ protected FuzzingAppender(String name) {
+ super(name, null, PatternLayout.createDefaultLayout(), true);
+ }
+
+ @PluginFactory
+ public static FuzzingAppender createAppender(@PluginAttribute("name") String name) {
+ return new FuzzingAppender(name);
+ }
+
+ @Override
+ public void append(LogEvent event) {
+ try {
+ getLayout().toByteArray(event);
+ } catch (Exception ignored) {
+ // Prevent exceptions from being logged to stderr.
+ }
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/TiffImageParserFuzzer.java b/examples/src/main/java/com/example/TiffImageParserFuzzer.java
new file mode 100644
index 00000000..5fa1af2d
--- /dev/null
+++ b/examples/src/main/java/com/example/TiffImageParserFuzzer.java
@@ -0,0 +1,31 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import java.io.IOException;
+import java.util.HashMap;
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
+import org.apache.commons.imaging.formats.tiff.TiffImageParser;
+
+// Found https://issues.apache.org/jira/browse/IMAGING-276.
+public class TiffImageParserFuzzer {
+ public static void fuzzerTestOneInput(byte[] input) {
+ try {
+ new TiffImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>());
+ } catch (IOException | ImageReadException ignored) {
+ }
+ }
+}
diff --git a/examples/src/main/java/com/example/TurboJpegFuzzer.java b/examples/src/main/java/com/example/TurboJpegFuzzer.java
new file mode 100644
index 00000000..b9ea715b
--- /dev/null
+++ b/examples/src/main/java/com/example/TurboJpegFuzzer.java
@@ -0,0 +1,59 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.example;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import org.libjpegturbo.turbojpeg.TJ;
+import org.libjpegturbo.turbojpeg.TJDecompressor;
+import org.libjpegturbo.turbojpeg.TJException;
+import org.libjpegturbo.turbojpeg.TJTransform;
+import org.libjpegturbo.turbojpeg.TJTransformer;
+
+public class TurboJpegFuzzer {
+ static byte[] buffer = new byte[128 * 128 * 4];
+
+ public static void fuzzerInitialize() throws TJException {
+ // Trigger an early load of the native library to show the coverage counters stats in libFuzzer.
+ new TJDecompressor();
+ }
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ try {
+ int flagsDecompress = data.consumeInt();
+ int flagsTransform = data.consumeInt();
+ int pixelFormat = data.consumeInt(TJ.PF_RGB, TJ.PF_CMYK);
+ // Specify explicit small target width/height so that we can reuse a
+ // fixed-size buffer.
+ int desiredWidth = data.consumeInt(1, 128);
+ int desiredHeight = data.consumeInt(1, 128);
+ int transformOp = data.consumeInt(TJTransform.OP_NONE, TJTransform.OP_ROT270);
+ int transformOptions = data.consumeInt();
+ int transformWidth = data.consumeBoolean() ? 128 : 64;
+ int transformHeight = data.consumeBoolean() ? 128 : 64;
+ TJDecompressor tjd;
+ if (data.consumeBoolean()) {
+ TJTransformer tjt = new TJTransformer(data.consumeRemainingAsBytes());
+ TJTransform tjf = new TJTransform(
+ 0, 0, transformWidth, transformHeight, transformOp, transformOptions, null);
+ tjd = tjt.transform(new TJTransform[] {tjf}, flagsTransform)[0];
+ } else {
+ tjd = new TJDecompressor(data.consumeRemainingAsBytes());
+ }
+ tjd.decompress(buffer, 0, 0, desiredWidth, 0, desiredHeight, pixelFormat, flagsDecompress);
+ } catch (Exception ignored) {
+ // We are not looking for Java exceptions, but segfaults and ASan reports.
+ }
+ }
+}
diff --git a/examples/src/main/native/com/example/BUILD.bazel b/examples/src/main/native/com/example/BUILD.bazel
new file mode 100644
index 00000000..7f23f75e
--- /dev/null
+++ b/examples/src/main/native/com/example/BUILD.bazel
@@ -0,0 +1,49 @@
+load("@fmeum_rules_jni//jni:defs.bzl", "cc_jni_library")
+
+cc_jni_library(
+ name = "native_asan",
+ srcs = [
+ "com_example_ExampleFuzzerWithNative.cpp",
+ ],
+ copts = [
+ "-fsanitize=fuzzer-no-link,address",
+ "-fno-sanitize-blacklist",
+ ],
+ linkopts = select({
+ "//:clang_on_linux": ["-fuse-ld=lld"],
+ "@platforms//os:windows": [
+ # Windows requires all symbols that should be imported from the main
+ # executable to be defined by an import lib.
+ "/wholearchive:clang_rt.asan_dll_thunk-x86_64.lib",
+ ],
+ "//conditions:default": [],
+ }),
+ visibility = ["//examples:__pkg__"],
+ deps = [
+ "//examples:example_fuzzer_with_native_lib.hdrs",
+ ],
+)
+
+cc_jni_library(
+ name = "native_ubsan",
+ srcs = [
+ "com_example_ExampleFuzzerWithNative.cpp",
+ ],
+ copts = [
+ "-fsanitize=fuzzer-no-link,undefined",
+ "-fno-sanitize-recover=all",
+ ],
+ linkopts = select({
+ "//:clang_on_linux": ["-fuse-ld=lld"],
+ "@platforms//os:windows": [
+ # Using the asan thunk is correct here as it contains symbols for
+ # UBSan and SanCov as well.
+ "/wholearchive:clang_rt.asan_dll_thunk-x86_64.lib",
+ ],
+ "//conditions:default": [],
+ }),
+ visibility = ["//examples:__pkg__"],
+ deps = [
+ "//examples:example_fuzzer_with_native_lib.hdrs",
+ ],
+)
diff --git a/examples/src/main/native/com/example/com_example_ExampleFuzzerWithNative.cpp b/examples/src/main/native/com/example/com_example_ExampleFuzzerWithNative.cpp
new file mode 100644
index 00000000..774e5998
--- /dev/null
+++ b/examples/src/main/native/com/example/com_example_ExampleFuzzerWithNative.cpp
@@ -0,0 +1,42 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "com_example_ExampleFuzzerWithNative.h"
+
+#include <limits>
+#include <string>
+
+// simple function containing a crash that requires coverage and string compare
+// instrumentation for the fuzzer to find
+__attribute__((optnone)) void parseInternal(const std::string &input) {
+ constexpr int bar = std::numeric_limits<int>::max() - 5;
+ // Crashes with UBSan.
+ if (bar + input[0] == 300) {
+ return;
+ }
+ if (input[0] == 'a' && input[1] == 'b' && input[5] == 'c') {
+ if (input.find("secret_in_native_library") != std::string::npos) {
+ // Crashes with ASan.
+ [[maybe_unused]] char foo = input[input.size() + 2];
+ }
+ }
+}
+
+JNIEXPORT jboolean JNICALL Java_com_example_ExampleFuzzerWithNative_parse(
+ JNIEnv *env, jobject o, jstring bytes) {
+ const char *input(env->GetStringUTFChars(bytes, nullptr));
+ parseInternal(input);
+ env->ReleaseStringUTFChars(bytes, input);
+ return false;
+}