Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update and simplify Jazzer integration #218

Merged
merged 4 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
build --action_env=CC=clang-10
build --action_env=CXX=clang++-10

# Workaround for https://github.com/bazelbuild/bazel/issues/3236
build --sandbox_tmpfs_path=/tmp

# Strict dependency check for C++ includes.
build --features=layering_check

Expand Down Expand Up @@ -64,6 +67,7 @@ build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_instrumentation=none
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan

build:oss-fuzz --//fuzzing:cc_engine=@rules_fuzzing_oss_fuzz//:oss_fuzz_engine
build:oss-fuzz --//fuzzing:java_engine=@rules_fuzzing_oss_fuzz//:oss_fuzz_java_engine
build:oss-fuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=oss-fuzz
build:oss-fuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=none

Expand Down
20 changes: 1 addition & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,25 +156,7 @@ The crash is saved under `/tmp/fuzzing/artifacts` and can be further inspected.

### Java fuzzing

You can write `java_fuzz_test`s through the [Jazzer][jazzer-doc] fuzzing engine. You will need to enable it in your WORKSPACE `rules_fuzzing_dependencies` call:

```python
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")

rules_fuzzing_dependencies(jazzer = True)

load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")

rules_fuzzing_init()

load("@jazzer//:repositories.bzl", "jazzer_dependencies")

jazzer_dependencies()

load("@jazzer//:init.bzl", "jazzer_init")

jazzer_init()
```
You can write `java_fuzz_test`s through the [Jazzer][jazzer-doc] fuzzing engine.

To use Jazzer, it is convenient to also define a `.bazelrc` configuration, similar to the C++ libFuzzer one above:

Expand Down
10 changes: 1 addition & 9 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")

rules_fuzzing_dependencies(jazzer = True)
rules_fuzzing_dependencies()

load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")

Expand All @@ -30,14 +30,6 @@ load("@fuzzing_py_deps//:requirements.bzl", "install_deps")

install_deps()

load("@jazzer//:repositories.bzl", "jazzer_dependencies")

jazzer_dependencies()

load("@jazzer//:init.bzl", "jazzer_init")

jazzer_init()

# The support for running the examples and unit tests.

http_archive(
Expand Down
10 changes: 9 additions & 1 deletion fuzzing/engines/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ java_fuzzing_engine(
name = "jazzer",
display_name = "Jazzer",
launcher = "jazzer_launcher.sh",
library = "@jazzer//agent:jazzer_api_compile_only",
library = ":jazzer_stub",
visibility = ["//visibility:public"],
)

java_library(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain in a comment the role of this rule? It seems to provide no functionality?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment.

name = "jazzer_stub",
exports = [
"@maven_jazzer//jar",
"@maven_jazzer_api//jar",
],
)
22 changes: 7 additions & 15 deletions fuzzing/private/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,28 @@ exports_files([
"util.bzl",
])

# Config settings needed for prebuilt engines.
config_setting(
name = "use_sanitizer_none",
name = "is_oss_fuzz",
flag_values = {
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "none",
"@rules_fuzzing//fuzzing:cc_engine": "@rules_fuzzing_oss_fuzz//:oss_fuzz_engine",
},
visibility = ["//visibility:public"],
)

config_setting(
name = "use_sanitizer_asan",
name = "use_asan",
flag_values = {
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "asan",
},
visibility = ["//visibility:public"],
)

config_setting(
name = "use_sanitizer_ubsan",
name = "use_ubsan",
flag_values = {
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "ubsan",
},
)

config_setting(
name = "use_oss_fuzz",
flag_values = {
"@rules_fuzzing//fuzzing:cc_engine": "@rules_fuzzing_oss_fuzz//:oss_fuzz_engine",
# This is required to make the setting an unambiguous specialization of
# the use_sanitizer_* settings.
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "none",
},
visibility = ["//visibility:public"],
)

exports_files([
Expand Down
87 changes: 54 additions & 33 deletions fuzzing/private/fuzz_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""The implementation of the {cc, java}_fuzz_test rules."""

load("@rules_fuzzing_oss_fuzz//:instrum.bzl", "native_library_sanitizer")
load("@rules_cc//cc:defs.bzl", "cc_binary")

# FIXME: Including this leads to a Stardoc error since defs.bzl is not visible. As a workaround, use native.java_binary.
Expand Down Expand Up @@ -213,6 +214,15 @@ def cc_fuzz_test(
test_timeout = timeout,
)

_ASAN_RUNTIME = Label("//fuzzing/private/runtime:asan")
_UBSAN_RUNTIME = Label("//fuzzing/private/runtime:ubsan")
_RUNTIME_BY_NAME = {
"asan": _ASAN_RUNTIME,
"ubsan": _UBSAN_RUNTIME,
"none": None,
}

# buildifier: disable=list-append
def java_fuzz_test(
name,
srcs = None,
Expand Down Expand Up @@ -264,6 +274,8 @@ def java_fuzz_test(
# this target directly. Instead, the binary should be built through the
# instrumented configuration.
raw_target_name = name + "_target_"
metadata_binary_name = name + "_metadata_"
metadata_deploy_jar_name = metadata_binary_name + "_deploy.jar"

# Determine a value for target_class heuristically using the same rules as
# those used by Bazel internally for main_class.
Expand All @@ -277,62 +289,71 @@ def java_fuzz_test(
name = name,
))
target_class_manifest_line = "Jazzer-Fuzz-Target-Class: %s" % target_class
binary_kwargs.setdefault("deps", [])

# Use += rather than append to allow users to pass in select() expressions for
# deps, which only support concatenation with +.
# Workaround for https://github.com/bazelbuild/bazel/issues/14157.
# buildifier: disable=list-append
binary_kwargs["deps"] += [engine]
binary_kwargs.setdefault("deploy_manifest_lines", [])
native.java_binary(
name = metadata_binary_name,
deploy_manifest_lines = [target_class_manifest_line],
tags = ["manual"],
)

# buildifier: disable=list-append
binary_kwargs["deploy_manifest_lines"] += [target_class_manifest_line]
# use += rather than append to allow users to pass in select() expressions for
# deps, which only support concatenation with +.
# workaround for https://github.com/bazelbuild/bazel/issues/14157.
if srcs:
binary_kwargs.setdefault("deps", [])
binary_kwargs["deps"] += [engine, metadata_deploy_jar_name]
else:
binary_kwargs.setdefault("runtime_deps", [])
binary_kwargs["runtime_deps"] += [engine, metadata_deploy_jar_name]

binary_kwargs.setdefault("jvm_flags", [])
binary_kwargs["jvm_flags"] = [
# Ensures that full stack traces are emitted for findings even in highly
# optimized code.
"-XX:-OmitStackTraceInFastThrow",
# Optimized for throughput rather than latency.
"-XX:+UseParallelGC",
# Ignore CriticalJNINatives if not available (JDK 18+).
"-XX:+IgnoreUnrecognizedVMOptions",
# Improves performance of Jazzer's native compare instrumentation.
"-XX:+CriticalJNINatives",
] + binary_kwargs["jvm_flags"]

# tags is not configurable and can thus use append.
binary_kwargs.setdefault("tags", []).append("manual")
native.java_binary(
name = raw_target_name,
srcs = srcs,
create_executable = False,
main_class = "com.code_intelligence.jazzer.Jazzer",
**binary_kwargs
)

raw_binary_name = name + "_raw_"
jazzer_fuzz_binary(
name = raw_binary_name,
agent = select({
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_agent_deploy.jar",
"//conditions:default": "@jazzer//agent:jazzer_agent_deploy.jar",
sanitizer = select({
"@rules_fuzzing//fuzzing/private:is_oss_fuzz": native_library_sanitizer,
"@rules_fuzzing//fuzzing/private:use_asan": "asan",
"@rules_fuzzing//fuzzing/private:use_ubsan": "ubsan",
"//conditions:default": "none",
}),
# Since the choice of sanitizer is explicit for local fuzzing, we also
# let it apply to projects with no native dependencies.
driver_java_only = select({
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_driver",
"@rules_fuzzing//fuzzing/private:use_sanitizer_none": "@jazzer//driver:jazzer_driver",
"@rules_fuzzing//fuzzing/private:use_sanitizer_asan": "@jazzer//driver:jazzer_driver_asan",
"@rules_fuzzing//fuzzing/private:use_sanitizer_ubsan": "@jazzer//driver:jazzer_driver_ubsan",
}, no_match_error = "Jazzer only supports the sanitizer settings: \"none\", \"asan\", \"ubsan\""),
driver_with_native = select({
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_driver_with_sanitizer",
"@rules_fuzzing//fuzzing/private:use_sanitizer_none": "@jazzer//driver:jazzer_driver",
"@rules_fuzzing//fuzzing/private:use_sanitizer_asan": "@jazzer//driver:jazzer_driver_asan",
"@rules_fuzzing//fuzzing/private:use_sanitizer_ubsan": "@jazzer//driver:jazzer_driver_ubsan",
}, no_match_error = "Jazzer only supports the sanitizer settings: \"none\", \"asan\", \"ubsan\""),
sanitizer_options = select({
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing//fuzzing/private:oss_fuzz_jazzer_sanitizer_options.sh",
"//conditions:default": "@rules_fuzzing//fuzzing/private:local_jazzer_sanitizer_options.sh",
"@rules_fuzzing//fuzzing/private:is_oss_fuzz": Label("//fuzzing/private:oss_fuzz_jazzer_sanitizer_options.sh"),
"//conditions:default": Label("//fuzzing/private:local_jazzer_sanitizer_options.sh"),
}),
sanitizer_runtime = select({
"@rules_fuzzing//fuzzing/private:is_oss_fuzz": _RUNTIME_BY_NAME[native_library_sanitizer],
"@rules_fuzzing//fuzzing/private:use_asan": _ASAN_RUNTIME,
"@rules_fuzzing//fuzzing/private:use_ubsan": _UBSAN_RUNTIME,
"//conditions:default": None,
}),
tags = ["manual"],
target = raw_target_name,
target_deploy_jar = raw_target_name + "_deploy.jar",
tags = ["manual"],
)

fuzzing_decoration(
name = name,
raw_binary = raw_binary_name,
# jazzer_fuzz_binary already instrumented the native dependencies.
instrument_binary = False,
engine = engine,
corpus = corpus,
dicts = dicts,
Expand Down
Loading