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

Support UBSan for local fuzzing #187

Merged
merged 1 commit into from
Dec 2, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
17 changes: 17 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ build:msan-libfuzzer-repro --//fuzzing:cc_engine=//fuzzing/engines:libfuzzer
build:msan-libfuzzer-repro --@rules_fuzzing//fuzzing:cc_engine_instrumentation=libfuzzer
build:msan-libfuzzer-repro --@rules_fuzzing//fuzzing:cc_engine_sanitizer=msan-origin-tracking

# LibFuzzer + UBSAN
build:ubsan-libfuzzer --//fuzzing:cc_engine=//fuzzing/engines:libfuzzer
build:ubsan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=libfuzzer
build:ubsan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan

# Honggfuzz + ASAN
build:asan-honggfuzz --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
build:asan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
Expand All @@ -48,6 +53,11 @@ build:msan-honggfuzz --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
build:msan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
build:msan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=msan

# Honggfuzz + UBSAN
build:ubsan-honggfuzz --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan

# Replay + ASAN
build:asan-replay --//fuzzing:cc_engine=//fuzzing/engines:replay
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_instrumentation=none
Expand All @@ -70,3 +80,10 @@ build:asan-jazzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=jazzer
build:asan-jazzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan
# Workaround for https://github.com/bazelbuild/bazel/issues/11128
build:asan-jazzer --//fuzzing:cc_engine_sanitizer=asan

# Jazzer + UBSAN
build:ubsan-jazzer --//fuzzing:java_engine=//fuzzing/engines:jazzer
build:ubsan-jazzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=jazzer
build:ubsan-jazzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan
# Workaround for https://github.com/bazelbuild/bazel/issues/11128
build:ubsan-jazzer --//fuzzing:cc_engine_sanitizer=ubsan
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The rule library currently provides support for C++ and Java fuzz tests. Support
* Multiple sanitizer configurations:
* [Address Sanitizer][asan-doc]
* [Memory Sanitizer][msan-doc]
* [Undefined Behavior Sanitizer][ubsan-doc]
* Corpora and dictionaries.
* Simple "bazel run/test" commands to build and run the fuzz tests.
* No need to understand the details of each fuzzing engine.
Expand Down Expand Up @@ -258,3 +259,4 @@ Check out the [`examples/`](examples/) directory, which showcases additional fea
[libfuzzer-doc]: https://llvm.org/docs/LibFuzzer.html
[jazzer-doc]: https://github.com/CodeIntelligenceTesting/jazzer
[msan-doc]: https://clang.llvm.org/docs/MemorySanitizer.html
[ubsan-doc]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
17 changes: 17 additions & 0 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ The fuzzing rules library defines the following Bazel configuration flags that a
* `asan`: [Address Sanitizer (ASAN)][asan-doc].
* `msan`: [Memory Sanitizer (MSAN)][msan-doc].
* `msan-origin-tracking`: MSAN with [origin tracking][msan-origin-tracking] enabled (useful for debugging crash reproducers; available separately due to it being 1.5-2x slower).
* `ubsan`: [Undefined Behavior Sanitizer (UBSAN)][ubsan-doc].

* `--@rules_fuzzing//fuzzing:cc_fuzzing_build_mode` is a bool flag that specifies whether the special [`FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` macro][fuzzing-build-mode] is defined during the build. This is turned on by default and most users should not need to change this flag.

Expand Down Expand Up @@ -180,6 +181,11 @@ build:msan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine=@rules_fuzzing//fuzzing
build:msan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=libfuzzer
build:msan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=msan

# --config=ubsan-libfuzzer
build:ubsan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine=@rules_fuzzing//fuzzing/engines:libfuzzer
build:ubsan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=libfuzzer
build:ubsan-libfuzzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan

# --config=asan-honggfuzz
build:asan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine=@rules_fuzzing//fuzzing/engines:honggfuzz
build:asan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
Expand All @@ -190,6 +196,11 @@ build:msan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine=@rules_fuzzing//fuzzing
build:msan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
build:msan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=msan

# --config=ubsan-honggfuzz
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine=@rules_fuzzing//fuzzing/engines:honggfuzz
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan

# --config=asan-replay
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine=@rules_fuzzing//fuzzing/engines:replay
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_instrumentation=none
Expand All @@ -204,6 +215,11 @@ build:jazzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=none
build:asan-jazzer --@rules_fuzzing//fuzzing:java_engine=@rules_fuzzing//fuzzing/engines:jazzer
build:asan-jazzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=jazzer
build:asan-jazzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan

# --config=ubsan-jazzer
build:ubsan-jazzer --@rules_fuzzing//fuzzing:java_engine=@rules_fuzzing//fuzzing/engines:jazzer
build:ubsan-jazzer --@rules_fuzzing//fuzzing:cc_engine_instrumentation=jazzer
build:ubsan-jazzer --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan
```

## Advanced topics
Expand Down Expand Up @@ -241,3 +257,4 @@ A fuzzing engine launcher script receives configuration through the following en
[msan-doc]: https://clang.llvm.org/docs/MemorySanitizer.html
[msan-origin-tracking]: https://clang.llvm.org/docs/MemorySanitizer.html#origin-tracking
[seed-corpus]: https://github.com/google/fuzzing/blob/master/docs/good-fuzz-target.md#seed-corpus
[ubsan-doc]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
16 changes: 16 additions & 0 deletions examples/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,19 @@ cc_fuzz_test(
"@bazel_tools//tools/cpp/runfiles",
],
)

cc_fuzz_test(
name = "ubsan_int_overflow_fuzz_test",
srcs = ["ubsan_int_overflow_fuzz_test.cc"],
tags = [
"no-oss-fuzz",
],
)

cc_fuzz_test(
name = "ubsan_function_ptr_fuzz_test",
srcs = ["ubsan_function_ptr_fuzz_test.cc"],
tags = [
"no-oss-fuzz",
],
)
20 changes: 20 additions & 0 deletions examples/java/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ java_fuzz_test(
],
)

java_fuzz_test(
name = "NativeUbsanFuncPtrFuzzTest",
srcs = ["com/example/NativeUbsanFuncPtrFuzzTest.java"],
deps = [
":native_ubsan_func_ptr",
],
)

# A native library that interfaces with Java through the JNI.
cc_binary(
name = "native",
Expand Down Expand Up @@ -99,3 +107,15 @@ cc_binary(
"@bazel_tools//tools/jdk:jni",
],
)

cc_binary(
name = "native_ubsan_func_ptr",
srcs = [
"com/example/NativeUbsanFuncPtrFuzzTest.cpp",
"com/example/NativeUbsanFuncPtrFuzzTest.h",
],
linkshared = True,
deps = [
"@bazel_tools//tools/jdk:jni",
],
)
37 changes: 37 additions & 0 deletions examples/java/com/example/NativeUbsanFuncPtrFuzzTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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.

// parse calls a function through a pointer of a mismatched type. This is
// detected by UBSAN's function check.

#include "NativeUbsanFuncPtrFuzzTest.h"

#include <cstddef>
#include <cstdint>

int parse_data(const uint16_t *data) {
return data[0] + data[1];
}

int (*mistyped_function_pointer)(const char *data);

JNIEXPORT int JNICALL Java_com_example_NativeUbsanFuncPtrFuzzTest_parse(
JNIEnv *env, jobject o, jstring bytes) {
const char *input(env->GetStringUTFChars(bytes, nullptr));
mistyped_function_pointer =
reinterpret_cast<int (*)(const char *)>(&parse_data);
int result = mistyped_function_pointer(input);
env->ReleaseStringUTFChars(bytes, input);
return result;
}
34 changes: 34 additions & 0 deletions examples/java/com/example/NativeUbsanFuncPtrFuzzTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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 <jni.h>
/* Header for class com_example_NativeUbsanFuncPtrFuzzTest */

#ifndef EXAMPLES_JAVA_COM_EXAMPLE_NATIVEUBSANFUNCPTRFUZZTEST_H_
#define EXAMPLES_JAVA_COM_EXAMPLE_NATIVEUBSANFUNCPTRFUZZTEST_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_NativeUbsanFuncPtrFuzzTest
* Method: parse
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT int JNICALL
Java_com_example_NativeUbsanFuncPtrFuzzTest_parse(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif // EXAMPLES_JAVA_COM_EXAMPLE_NATIVEUBSANFUNCPTRFUZZTEST_H_
35 changes: 35 additions & 0 deletions examples/java/com/example/NativeUbsanFuncPtrFuzzTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2021 Google LLC
//
// 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;

// The native function parse calls a function through a pointer of a mismatched
// type. This is detected by UBSAN's function check.
public class NativeUbsanFuncPtrFuzzTest {

static {
System.loadLibrary("native_ubsan_func_ptr");
}

public static void fuzzerTestOneInput(FuzzedDataProvider data) {
String stringData = data.consumeRemainingAsString();
if (stringData.length() > 10) {
parse(stringData);
}
}

private static native void parse(String data);
}
36 changes: 36 additions & 0 deletions examples/ubsan_function_ptr_fuzz_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.

// A fuzz target that calls a function through a pointer of a mismatched type.
// This is detected by UBSAN's function check and requires the UBSAN C++
// runtime.

#include <cstddef>
#include <cstdint>

int parse_data(const uint16_t *data) {
return data[0] + data[1];
}

int (*mistyped_function_pointer)(const uint8_t *data);

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 2) {
return 0;
}
mistyped_function_pointer =
reinterpret_cast<int (*)(const uint8_t *)>(parse_data);
mistyped_function_pointer(data);
return 0;
}
29 changes: 29 additions & 0 deletions examples/ubsan_int_overflow_fuzz_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.

// A fuzz target that triggers a signed integer overflow, which is undefined
// behavior and detected by UBSAN's signed-integer-overflow check.

#include <cstddef>
#include <cstdint>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size == 0) {
return 0;
}
int k = 0x7fffffff;
k += data[0];
// Use k.
return k & 0;
}
3 changes: 3 additions & 0 deletions fuzzing/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ string_flag(
# MSAN + origin tracking enabled.
# Useful for debugging crash reproducers, 1.5-2x slower.
"msan-origin-tracking",
# Undefined Behavior sanitizer (UBSAN).
# See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
"ubsan",
],
visibility = ["//visibility:public"],
)
Expand Down
1 change: 1 addition & 0 deletions fuzzing/instrum_opts.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ sanitizer_configs = {
"asan": instrum_defaults.asan,
"msan": instrum_defaults.msan,
"msan-origin-tracking": instrum_defaults.msan_origin_tracking,
"ubsan": instrum_defaults.ubsan,
}
7 changes: 7 additions & 0 deletions fuzzing/private/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ config_setting(
},
)

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

config_setting(
name = "use_oss_fuzz",
flag_values = {
Expand Down
6 changes: 4 additions & 2 deletions fuzzing/private/fuzz_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,14 @@ def java_fuzz_test(
"@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",
}, no_match_error = "Jazzer only supports the sanitizer settings \"none\" and \"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",
}, no_match_error = "Jazzer only supports the sanitizer settings \"none\" and \"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",
Expand Down
21 changes: 21 additions & 0 deletions fuzzing/private/instrum_opts.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,25 @@ instrum_defaults = struct(
],
linkopts = ["-fsanitize=memory"],
),
ubsan = _make_opts(
copts = [
"-fsanitize=undefined",
# Enable most of the checks enabled in OSS-Fuzz:
# https://github.com/google/oss-fuzz/blob/a896ee749769bd236299041461784f483649fe80/infra/base-images/base-builder/Dockerfile#L77
# The only exception is unsigned-integer-overflow, which is not UB,
# but enabled in OSS-Fuzz in silent mode as an additional coverage
# signal. We do not do this here as it would introduce additional
# complexity (setting UBSAN_OPTIONS) to the local mode.
"-fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr",
"-fno-sanitize-recover=all",
],
linkopts = [
"-fsanitize=undefined",
# Bazel uses clang, not clang++, as the linker, which does not link
# the C++ UBSan runtime library by default, but can be instructed to
# do so with a flag.
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-896613570
"-fsanitize-link-c++-runtime",
],
),
)