aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Meumertzheim <meumertzheim@code-intelligence.com>2021-06-09 10:03:53 +0200
committerFabian Meumertzheim <fabian@meumertzhe.im>2021-06-09 11:48:20 +0200
commit224e8d00c26d19a78de1720459e3c5b403ae36ca (patch)
treefbb98af54cb3b218c4dd66689537ec2b4e0fdfb0
parentedc2afa53eaab4e036dae4c418b88d0b3e669949 (diff)
downloadjazzer-api-224e8d00c26d19a78de1720459e3c5b403ae36ca.tar.gz
Add support for UBSan
-rw-r--r--BUILD.bazel11
-rw-r--r--README.md17
-rw-r--r--bazel/fuzz_target.bzl11
-rw-r--r--driver/BUILD.bazel14
-rw-r--r--driver/libfuzzer_fuzz_target.cpp5
-rw-r--r--examples/BUILD.bazel20
-rw-r--r--examples/src/main/java/com/example/ExampleFuzzerWithNative.java6
-rw-r--r--examples/src/main/native/BUILD.bazel24
-rw-r--r--examples/src/main/native/com_example_ExampleFuzzerWithNative.cpp8
9 files changed, 100 insertions, 16 deletions
diff --git a/BUILD.bazel b/BUILD.bazel
index 965c99b1..8c3cbcd7 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -57,6 +57,17 @@ sh_binary(
],
)
+sh_binary(
+ name = "jazzer_ubsan",
+ srcs = ["//bazel:jazzer_wrapper.sh"],
+ args = [
+ "$(rootpath //driver:jazzer_driver_ubsan)",
+ ],
+ data = [
+ "//driver:jazzer_driver_ubsan",
+ ],
+)
+
exports_files([
"jazzer-api.pom",
])
diff --git a/README.md b/README.md
index 4e0b42b0..9fb5bff7 100644
--- a/README.md
+++ b/README.md
@@ -401,15 +401,18 @@ via `--ignore=<token_1>,<token2>`.
Jazzer supports fuzzing of native libraries loaded by the JVM, for example via `System.load()`. For the fuzzer to get
coverage feedback, these libraries have to be compiled with `-fsanitize=fuzzer-no-link`.
-Additional sanitizers such as AddressSanitizer are often desirable to uncover bugs inside the native libraries. This
-requires compiling the library with `-fsanitize=fuzzer-no-link,address` and using the asan-ified driver available
-as the Bazel target `//:jazzer_asan`.
+Additional sanitizers such as AddressSanitizer or UndefinedBehaviorSanitizer are often desirable to uncover bugs inside
+the native libraries. The required compilation flags for native libraries are as follows:
+ - *AddressSanitizer*: `-fsanitize=fuzzer-no-link,address`
+ - *UndefinedBehaviorSanitizer*: `-fsanitize=fuzzer-no-link,undefined` (add `-fno-sanitize-recover=all` to crash on UBSan reports)
-**Note:** Sanitizers other than AddressSanitizer are not yet supported. Furthermore, due to the nature of the JVM's GC,
-LeakSanitizer reports currently too many false positives to be useful and are thus disabled.
+Then, use the appropriate driver `//:jazzer_asan` or `//:jazzer_ubsan`.
-The fuzz target `ExampleFuzzerWithNative` in the `examples/` directory contains a minimal working example for fuzzing
-with native libraries. Also see `TurboJpegFuzzer` for a real-world example.
+**Note:** Sanitizers other than AddressSanitizer and UndefinedBehaviorSanitizer are not yet supported.
+Furthermore, due to the nature of the JVM's GC, LeakSanitizer reports too many false positives to be useful and is thus disabled.
+
+The fuzz targets `ExampleFuzzerWithNativeASan` and `ExampleFuzzerWithNativeUBSan` in the `examples/` directory contain
+minimal working examples for fuzzing with native libraries. Also see `TurboJpegFuzzer` for a real-world example.
### Fuzzing with Custom Mutators
diff --git a/bazel/fuzz_target.bzl b/bazel/fuzz_target.bzl
index 051f9169..e920e1a7 100644
--- a/bazel/fuzz_target.bzl
+++ b/bazel/fuzz_target.bzl
@@ -20,7 +20,7 @@ def java_fuzz_target_test(
deps = [],
hook_classes = [],
native_libs = [],
- use_asan = False,
+ sanitizer = None,
visibility = None,
tags = [],
fuzzer_args = [],
@@ -52,7 +52,14 @@ def java_fuzz_target_test(
if native_libs_paths != "":
additional_args.append("--jvm_args=-Djava.library.path=" + native_libs_paths)
- driver = "//driver:jazzer_driver_asan" if use_asan else "//driver:jazzer_driver"
+ if sanitizer == None:
+ driver = "//driver:jazzer_driver"
+ elif sanitizer == "address":
+ driver = "//driver:jazzer_driver_asan"
+ elif sanitizer == "undefined":
+ driver = "//driver:jazzer_driver_ubsan"
+ else:
+ fail("Invalid sanitizer: " + sanitizer)
native.sh_test(
name = name,
diff --git a/driver/BUILD.bazel b/driver/BUILD.bazel
index 4fd89e5f..28b5a85e 100644
--- a/driver/BUILD.bazel
+++ b/driver/BUILD.bazel
@@ -85,6 +85,20 @@ cc_binary(
],
linkopts = [
"-fsanitize=address",
+ "-rdynamic",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [":driver_lib"],
+)
+
+cc_binary(
+ name = "jazzer_driver_ubsan",
+ data = [
+ "//agent:jazzer_agent_deploy.jar",
+ ],
+ linkopts = [
+ "-fsanitize=undefined",
+ "-rdynamic",
],
visibility = ["//visibility:public"],
deps = [":driver_lib"],
diff --git a/driver/libfuzzer_fuzz_target.cpp b/driver/libfuzzer_fuzz_target.cpp
index 8bbed9a1..c2003d02 100644
--- a/driver/libfuzzer_fuzz_target.cpp
+++ b/driver/libfuzzer_fuzz_target.cpp
@@ -28,6 +28,11 @@ const char *__asan_default_options() {
// We use a distinguished exit code to recognize ASan crashes in tests.
return "detect_leaks=0,exitcode=76";
}
+
+const char *__ubsan_default_options() {
+ // We use a distinguished exit code to recognize UBSan crashes in tests.
+ return "exitcode=76";
+}
}
namespace {
diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel
index b2d021d0..d7f0f8cd 100644
--- a/examples/BUILD.bazel
+++ b/examples/BUILD.bazel
@@ -14,15 +14,27 @@ java_fuzz_target_test(
)
java_fuzz_target_test(
- name = "ExampleFuzzerWithNative",
+ name = "ExampleFuzzerWithASan",
srcs = [
"src/main/java/com/example/ExampleFuzzerWithNative.java",
],
- native_libs = ["//examples/src/main/native"],
+ native_libs = ["//examples/src/main/native:native_asan"],
+ sanitizer = "address",
+ # Bazel creates shared libraries with an incorrect extension on macOS.
+ tags = ["broken-on-darwin"],
+ target_class = "com.example.ExampleFuzzerWithNative",
+)
+
+java_fuzz_target_test(
+ name = "ExampleFuzzerWithUBSan",
+ srcs = [
+ "src/main/java/com/example/ExampleFuzzerWithNative.java",
+ ],
+ native_libs = ["//examples/src/main/native:native_ubsan"],
+ sanitizer = "undefined",
# Bazel creates shared libraries with an incorrect extension on macOS.
tags = ["broken-on-darwin"],
target_class = "com.example.ExampleFuzzerWithNative",
- use_asan = True,
)
java_fuzz_target_test(
@@ -208,9 +220,9 @@ java_fuzz_target_test(
native_libs = [
"@libjpeg_turbo//:turbojpeg_native",
],
+ sanitizer = "address",
tags = ["manual"],
target_class = "com.example.TurboJpegFuzzer",
- use_asan = True,
deps = [
"@libjpeg_turbo//:turbojpeg_java",
],
diff --git a/examples/src/main/java/com/example/ExampleFuzzerWithNative.java b/examples/src/main/java/com/example/ExampleFuzzerWithNative.java
index 853501bf..071446aa 100644
--- a/examples/src/main/java/com/example/ExampleFuzzerWithNative.java
+++ b/examples/src/main/java/com/example/ExampleFuzzerWithNative.java
@@ -18,7 +18,11 @@ import com.code_intelligence.jazzer.api.FuzzedDataProvider;
public class ExampleFuzzerWithNative {
static {
- System.loadLibrary("native");
+ try {
+ System.loadLibrary("native_asan");
+ } catch (UnsatisfiedLinkError e) {
+ System.loadLibrary("native_ubsan");
+ }
}
public static void fuzzerTestOneInput(FuzzedDataProvider data) {
diff --git a/examples/src/main/native/BUILD.bazel b/examples/src/main/native/BUILD.bazel
index 16b48419..df24bb37 100644
--- a/examples/src/main/native/BUILD.bazel
+++ b/examples/src/main/native/BUILD.bazel
@@ -1,7 +1,7 @@
load("@rules_cc//cc:defs.bzl", "cc_binary")
cc_binary(
- name = "native",
+ name = "native_asan",
srcs = [
"com_example_ExampleFuzzerWithNative.cpp",
"com_example_ExampleFuzzerWithNative.h",
@@ -18,3 +18,25 @@ cc_binary(
"@bazel_tools//tools/jdk:jni",
],
)
+
+cc_binary(
+ name = "native_ubsan",
+ srcs = [
+ "com_example_ExampleFuzzerWithNative.cpp",
+ "com_example_ExampleFuzzerWithNative.h",
+ ],
+ copts = [
+ "-fsanitize=fuzzer-no-link,undefined",
+ "-fno-sanitize-recover=all",
+ # Workaround for https://github.com/bazelbuild/bazel/issues/11122.
+ "-fno-sanitize=vptr,function",
+ ],
+ linkopts = [
+ "-fsanitize=fuzzer-no-link,undefined",
+ ],
+ linkshared = True,
+ visibility = ["//examples:__pkg__"],
+ deps = [
+ "@bazel_tools//tools/jdk:jni",
+ ],
+)
diff --git a/examples/src/main/native/com_example_ExampleFuzzerWithNative.cpp b/examples/src/main/native/com_example_ExampleFuzzerWithNative.cpp
index 434c3d5b..774e5998 100644
--- a/examples/src/main/native/com_example_ExampleFuzzerWithNative.cpp
+++ b/examples/src/main/native/com_example_ExampleFuzzerWithNative.cpp
@@ -14,14 +14,20 @@
#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) {
- // BOOM
+ // Crashes with ASan.
[[maybe_unused]] char foo = input[input.size() + 2];
}
}