From 9b3d9a84d642eab3b6844bccdae175244c41ec4d Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Mon, 3 Jan 2022 17:52:23 +0100 Subject: [PATCH] Update jazzer (#181) * Update Jazzer The new Jazzer version includes logic to find libjvm.so, improved instrumentation for the Map interface as well as support for M1 Macs. * Symlink missing local_jdk runfiles in OSS-Fuzz * Create Java native libraries with .dylib extension on macOS * Test Java examples in the CI on macOS The newest Jazzer version finds libjvm.dylib on macOS. * Add more comments to java_fuzz_test examples --- .github/workflows/bazel_test.yml | 3 +- examples/java/BUILD | 106 +++++++++++++++++++++++++++---- fuzzing/private/java_utils.bzl | 13 ++-- fuzzing/repositories.bzl | 6 +- 4 files changed, 102 insertions(+), 26 deletions(-) diff --git a/.github/workflows/bazel_test.yml b/.github/workflows/bazel_test.yml index da75411..ed76d62 100644 --- a/.github/workflows/bazel_test.yml +++ b/.github/workflows/bazel_test.yml @@ -135,5 +135,4 @@ jobs: uses: actions/checkout@v2 - name: Run regression tests on macOS run: | - bazel test --verbose_failures --test_output=all \ - -- //examples/... -//examples/java:all + bazel test --verbose_failures --test_output=all //examples/... diff --git a/examples/java/BUILD b/examples/java/BUILD index 5c23abe..c35edd2 100644 --- a/examples/java/BUILD +++ b/examples/java/BUILD @@ -52,46 +52,110 @@ java_fuzz_test( tags = [ "no-oss-fuzz", ], - deps = [ - ":native", - ], + # The JVM expects a native library on macOS to have the .dylib extension, + # but due to a bug in Bazel the shared library extension defaults to .so + # there. This can be worked around by specifying the desired extension in + # the name of the rule and selecting the correct one based on the platform. + # See https://github.com/bazelbuild/bazel/issues/11082. + deps = select({ + "@platforms//os:macos": [":libnative.dylib"], + "//conditions:default": [":native"], + }), ) +# A Java fuzz test with a native library, both of which have declared data +# dependencies that they can access at runtime. java_fuzz_test( name = "NativeRunfileFuzzTest", srcs = ["com/example/NativeRunfileFuzzTest.java"], data = [ "corpus_0.txt", ], - deps = [ - ":native_runfile", + # See NativeFuzzTest for why this uses a select. + deps = select({ + "@platforms//os:macos": [":libnative_runfile.dylib"], + "//conditions:default": [":native_runfile"], + }) + [ "@bazel_tools//tools/java/runfiles", ], ) +# A Java fuzz test with a native library that calls a function through a pointer +# of an incorrect type, which is detected by UBSan. java_fuzz_test( name = "NativeUbsanFuncPtrFuzzTest", srcs = ["com/example/NativeUbsanFuncPtrFuzzTest.java"], - deps = [ - ":native_ubsan_func_ptr", - ], + deps = select({ + "@platforms//os:macos": [":libnative_ubsan_func_ptr.dylib"], + "//conditions:default": [":native_ubsan_func_ptr"], + }), ) # A native library that interfaces with Java through the JNI. +# It contains an out-of-bounds read is detected by ASan. cc_binary( name = "native", + # Build as a shared library that can be loaded by a Java application at + # runtime via System.loadLibrary(). + linkshared = True, + tags = ["manual"], + deps = [ + ":native_lib", + ], +) + +# The same shared library as :native, but with the correct extension for macOS. +# See the comment on :NativeFuzzTest for why this is needed. +cc_binary( + name = "libnative.dylib", + linkshared = True, + tags = ["manual"], + deps = [ + ":native_lib", + ], +) + +# The implementation shared by :native and :libnative.dylib, which differ only +# in the name of the resulting shared library. +cc_library( + name = "native_lib", srcs = [ "com/example/NativeFuzzTest.cpp", "com/example/NativeFuzzTest.h", ], - linkshared = True, deps = [ "@bazel_tools//tools/jdk:jni", ], + # Required because :native and :libnative.dylib to not reference any symbols + # of this library, which means that it wouldn't be linked at all without + # this. + alwayslink = True, ) +# A shared library that demonstrates that fuzz targets can find their Bazel +# data dependencies at runtime, both from Java and native code. cc_binary( name = "native_runfile", + linkshared = True, + tags = ["manual"], + deps = [ + ":native_runfile_lib", + ], +) + +# The same shared library as :native_runfile, but with the correct extension for +# macOS. See the comment on :NativeFuzzTest for why this is needed. +cc_binary( + name = "libnative_runfile.dylib", + linkshared = True, + tags = ["manual"], + deps = [ + ":native_runfile_lib", + ], +) + +cc_library( + name = "native_runfile_lib", srcs = [ "com/example/NativeRunfileFuzzTest.cpp", "com/example/NativeRunfileFuzzTest.h", @@ -99,23 +163,39 @@ cc_binary( data = [ "corpus_1.txt", ], - # Build as a shared library that can be loaded by a Java application at - # runtime via System.loadLibrary(). - linkshared = True, deps = [ "@bazel_tools//tools/cpp/runfiles", "@bazel_tools//tools/jdk:jni", ], + alwayslink = True, ) cc_binary( name = "native_ubsan_func_ptr", + linkshared = True, + tags = ["manual"], + deps = [ + ":native_ubsan_func_ptr_lib", + ], +) + +cc_binary( + name = "libnative_ubsan_func_ptr.dylib", + linkshared = True, + tags = ["manual"], + deps = [ + ":native_ubsan_func_ptr_lib", + ], +) + +cc_library( + name = "native_ubsan_func_ptr_lib", srcs = [ "com/example/NativeUbsanFuncPtrFuzzTest.cpp", "com/example/NativeUbsanFuncPtrFuzzTest.h", ], - linkshared = True, deps = [ "@bazel_tools//tools/jdk:jni", ], + alwayslink = True, ) diff --git a/fuzzing/private/java_utils.bzl b/fuzzing/private/java_utils.bzl index 95c05f0..0e1aed7 100644 --- a/fuzzing/private/java_utils.bzl +++ b/fuzzing/private/java_utils.bzl @@ -107,14 +107,11 @@ source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/ # Export the env variables required for subprocesses to find their runfiles. runfiles_export_envvars -# Determine the path to load libjvm.so from, either relative to the location of -# the java binary or to $JAVA_HOME, if set. On OSS-Fuzz, the path is provided in -# JVM_LD_LIBRARY_PATH. -JAVA_BIN=$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$(which java)") -JAVA_HOME=${JAVA_HOME:-${JAVA_BIN%/bin/java}} -# The location of libjvm.so relative to the JDK differs between JDK <= 8 and 9+. -JVM_LD_LIBRARY_PATH=${JVM_LD_LIBRARY_PATH:-"$JAVA_HOME/lib/server:$JAVA_HOME/lib/amd64/server"} -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$JVM_LD_LIBRARY_PATH +# When the runfiles tree exists but does not contain local_jdk, this script is +# executing on OSS-Fuzz. Link the current JAVA_HOME into the runfiles tree. +if [ -d "$0.runfiles" ] && [ ! -d "$0.runfiles/local_jdk" ]; then + ln -s "$JAVA_HOME" "$0.runfiles/local_jdk" +fi """ script_format_part = """ diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl index 04195ad..a9dc8c9 100644 --- a/fuzzing/repositories.bzl +++ b/fuzzing/repositories.bzl @@ -81,7 +81,7 @@ def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = False maybe( http_archive, name = "jazzer", - sha256 = "3cb2177974e81b70627f3a2bcdae5257e047d1aa23164a84a9a7bf8b7372e329", - strip_prefix = "jazzer-5d23f7b6bbb188fb4976f7d8b641b0e3d7655970", - url = "https://github.com/CodeIntelligenceTesting/jazzer/archive/5d23f7b6bbb188fb4976f7d8b641b0e3d7655970.zip", + sha256 = "c55889c235501498ca7436f57974ea59f0dc43e9effd64e13ce0c535265b8224", + strip_prefix = "jazzer-4434041f088365acf2a561e678bf9d61a7aa5dff", + url = "https://github.com/CodeIntelligenceTesting/jazzer/archive/4434041f088365acf2a561e678bf9d61a7aa5dff.zip", )