Add libfuzzer support

Adds the build support for using libfuzzer controlled by setting
`crashpad_use_libfuzzer=true`.

Also adds a first fuzzer (for ElfImageReader). Currently only runs on
Linux, but should work on Fuchsia too with some minor fixes (not sure
yet whether the fixes required are toolchain or in our build setup).

Run as:
  out/lin/elf_image_reader_fuzzer snapshot/elf/elf_image_reader_fuzzer_corpus/
hits an OOM pretty quickly in trying to allocate a giant buffer.

Bug: crashpad:30, crashpad:196, crashpad:233
Change-Id: Idd3ca11fe00319b8b29e029d5e13b17bfd518ea0
Reviewed-on: https://chromium-review.googlesource.com/1083451
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Scott Graham 2018-06-04 16:16:19 -07:00 committed by Commit Bot
parent 3edb7869da
commit 9a97daff39
10 changed files with 206 additions and 0 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@
/third_party/fuchsia/qemu
/third_party/fuchsia/sdk
/third_party/gtest/gtest
/third_party/libfuzzer
/third_party/linux/.cipd
/third_party/linux/clang
/third_party/linux/sysroot

3
DEPS
View File

@ -30,6 +30,9 @@ deps = {
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'd5a36d3c51a7a270afc2c888baaaec2a6e496219',
'crashpad/third_party/libfuzzer/src':
Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
'fda403cf93ecb8792cb1d061564d89a6553ca020',
'crashpad/third_party/zlib/zlib':
Var('chromium_git') + '/chromium/src/third_party/zlib@' +
'13dc246a58e4b72104d35f9b1809af95221ebda7',

View File

@ -37,3 +37,15 @@ group("default_exe_manifest_win") {
]
}
}
config("crashpad_fuzzer_flags") {
cflags = [
"-fsanitize=address",
"-fsanitize-address-use-after-scope",
"-fsanitize=fuzzer",
]
ldflags = [
"-fsanitize=address",
]
}

View File

@ -46,6 +46,10 @@ declare_args() {
# and logging. When false, enables the release configuration, with additional
# optimizations.
is_debug = false
# When true, build all code with -fsanitize=fuzzer, and enable various
# *_fuzzer targets.
crashpad_use_libfuzzer = false
}
_default_configs = [
@ -53,6 +57,10 @@ _default_configs = [
"//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors",
]
if (crashpad_use_libfuzzer) {
_default_configs += [ "//build:crashpad_fuzzer_flags" ]
}
_default_executable_configs =
_default_configs + [
"//third_party/mini_chromium/mini_chromium/build:executable",

View File

@ -0,0 +1,46 @@
# Copyright 2018 The Crashpad Authors. All rights reserved.
#
# 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.
import("crashpad_buildconfig.gni")
import("test.gni")
template("fuzzer_test") {
if (crashpad_is_standalone && crashpad_use_libfuzzer) {
test(target_name) {
forward_variables_from(invoker,
[
"cflags",
"cflags_cc",
"check_includes",
"defines",
"include_dirs",
"sources",
])
configs += [ "..:crashpad_config" ]
if (defined(invoker.deps)) {
deps = invoker.deps
}
deps += [ "../third_party/libfuzzer" ]
if (!defined(invoker.cflags)) {
cflags = []
}
cflags += [ "-fsanitize=fuzzer" ]
}
} else {
not_needed(invoker, "*")
group(target_name) {
}
}
}

View File

@ -13,6 +13,7 @@
# limitations under the License.
import("../build/crashpad_buildconfig.gni")
import("../build/crashpad_fuzzer_test.gni")
if (crashpad_is_in_chromium) {
import("//build/config/compiler/compiler.gni")
@ -238,6 +239,17 @@ if (crashpad_is_win) {
}
}
fuzzer_test("elf_image_reader_fuzzer") {
sources = [
"elf/elf_image_reader_fuzzer.cc",
]
deps = [
":snapshot",
"../third_party/mini_chromium:base",
]
}
static_library("test_support") {
testonly = true

View File

@ -0,0 +1,75 @@
// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// 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 <inttypes.h>
#include "base/logging.h"
#include "snapshot/elf/elf_image_reader.h"
#include "util/process/process_memory.h"
using namespace crashpad;
class FakeProcessMemory : public ProcessMemory {
public:
FakeProcessMemory(const uint8_t* data, size_t size, VMAddress fake_base)
: data_(data), size_(size), fake_base_(fake_base) {}
ssize_t ReadUpTo(VMAddress address,
size_t size,
void* buffer) const override {
VMAddress offset_in_data = address - fake_base_;
if (offset_in_data > size_)
return -1;
ssize_t read_size = std::min(size_ - offset_in_data, size);
memcpy(buffer, &data_[offset_in_data], read_size);
return read_size;
}
private:
const uint8_t* data_;
size_t size_;
VMAddress fake_base_;
};
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
// Swallow all logs to avoid spam.
logging::SetLogMessageHandler(
[](logging::LogSeverity, const char*, int, size_t, const std::string&) {
return true;
});
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
constexpr size_t kBase = 0x10000;
FakeProcessMemory process_memory(data, size, kBase);
ProcessMemoryRange process_memory_range;
process_memory_range.Initialize(&process_memory, true, kBase, size);
ElfImageReader reader;
if (!reader.Initialize(process_memory_range, kBase))
return 0;
ElfImageReader::NoteReader::Result result;
std::string note_name;
std::string note_desc;
ElfImageReader::NoteReader::NoteType note_type;
auto notes = reader.Notes(-1);
while ((result = notes->NextNote(&note_name, &note_type, &note_desc)) ==
ElfImageReader::NoteReader::Result::kSuccess) {
LOG(ERROR) << note_name << note_type << note_desc;
}
return 0;
}

Binary file not shown.

49
third_party/libfuzzer/BUILD.gn vendored Normal file
View File

@ -0,0 +1,49 @@
# Copyright 2018 The Crashpad Authors. All rights reserved.
#
# 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.
source_set("libfuzzer") {
if (crashpad_use_libfuzzer) {
sources = [
"src/FuzzerClangCounters.cpp",
"src/FuzzerCrossOver.cpp",
"src/FuzzerDriver.cpp",
"src/FuzzerExtFunctionsDlsym.cpp",
"src/FuzzerExtFunctionsDlsymWin.cpp",
"src/FuzzerExtFunctionsWeak.cpp",
"src/FuzzerExtFunctionsWeakAlias.cpp",
"src/FuzzerExtraCounters.cpp",
"src/FuzzerIO.cpp",
"src/FuzzerIOPosix.cpp",
"src/FuzzerIOWindows.cpp",
"src/FuzzerLoop.cpp",
"src/FuzzerMain.cpp",
"src/FuzzerMerge.cpp",
"src/FuzzerMutate.cpp",
"src/FuzzerSHA1.cpp",
"src/FuzzerShmemPosix.cpp",
"src/FuzzerShmemWindows.cpp",
"src/FuzzerTracePC.cpp",
"src/FuzzerUtil.cpp",
"src/FuzzerUtilDarwin.cpp",
"src/FuzzerUtilLinux.cpp",
"src/FuzzerUtilPosix.cpp",
"src/FuzzerUtilWindows.cpp",
]
configs -= [
"//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors",
"//build:crashpad_fuzzer_flags",
]
}
}