Commit b00aaaba authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Zucchini] Add ELF fuzzer

This CL introduces a fuzzer for the ELF disassemblers in Zucchini. I
have already uploaded some corpus files to the clusterfuzz-corpus
Google Storage bucket.

Achieves ~700 exec/s locally. This is on-par with the DEX and Win32
disassemblers as it requires a largish representative file to serve
as a test. (Recommendation is ~1000 exec/s).

Brings up coverage of ELF related code from 0-30% to 80-100%

I expect this will find quite a few crashes early on but should
stabilize within a couple of weeks; est. 1-2 bugfixes per day
based on how DEX and Win32 went. Mostly checked_casts and bounds
issues.

Bug: 1013641
Change-Id: I205135547cad2a95e59f99d7f040c13d72c45b59
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1856624
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Reviewed-by: default avatarEtienne Pierre-Doray <etiennep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705245}
parent cd3a0961
...@@ -5,10 +5,21 @@ ...@@ -5,10 +5,21 @@
import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni") import("//third_party/protobuf/proto_library.gni")
static_library("zucchini_fuzz_utils") {
sources = [
"fuzz_utils.cc",
"fuzz_utils.h",
]
deps = [
"//base",
"//components/zucchini:zucchini_lib",
]
}
# To download the corpus for local fuzzing use: # To download the corpus for local fuzzing use:
# gsutil -m rsync \ # gsutil -m rsync \
# gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_dex_fuzzer \ # gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_dex_fuzzer \
# components/zucchini/fuzzing/testdata/disassembler_dex_fuzzer # components/zucchini/fuzzing/testdata/disassembler_dex_fuzzer/
fuzzer_test("zucchini_disassembler_dex_fuzzer") { fuzzer_test("zucchini_disassembler_dex_fuzzer") {
sources = [ sources = [
"disassembler_dex_fuzzer.cc", "disassembler_dex_fuzzer.cc",
...@@ -22,12 +33,28 @@ fuzzer_test("zucchini_disassembler_dex_fuzzer") { ...@@ -22,12 +33,28 @@ fuzzer_test("zucchini_disassembler_dex_fuzzer") {
# To download the corpus for local fuzzing use: # To download the corpus for local fuzzing use:
# gsutil -m rsync \ # gsutil -m rsync \
# gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_win32_fuzzer \ # gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_win32_fuzzer \
# components/zucchini/fuzzing/testdata/disassembler_win32_fuzzer # components/zucchini/fuzzing/testdata/disassembler_win32_fuzzer/
fuzzer_test("zucchini_disassembler_win32_fuzzer") { fuzzer_test("zucchini_disassembler_win32_fuzzer") {
sources = [ sources = [
"disassembler_win32_fuzzer.cc", "disassembler_win32_fuzzer.cc",
] ]
deps = [ deps = [
":zucchini_fuzz_utils",
"//base",
"//components/zucchini:zucchini_lib",
]
}
# To download the corpus for local fuzzing use:
# gsutil -m rsync \
# gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_elf_fuzzer \
# components/zucchini/fuzzing/testdata/disassembler_elf_fuzzer/
fuzzer_test("zucchini_disassembler_elf_fuzzer") {
sources = [
"disassembler_elf_fuzzer.cc",
]
deps = [
":zucchini_fuzz_utils",
"//base", "//base",
"//components/zucchini:zucchini_lib", "//components/zucchini:zucchini_lib",
] ]
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
#include "components/zucchini/buffer_view.h"
#include "components/zucchini/disassembler.h"
#include "components/zucchini/disassembler_elf.h"
#include "components/zucchini/fuzzers/fuzz_utils.h"
namespace {
struct Environment {
Environment() { logging::SetMinLogLevel(logging::LOG_FATAL); }
};
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static Environment env;
if (!size)
return 0;
// Prepare data.
std::vector<uint8_t> mutable_data(data, data + size);
zucchini::ConstBufferView image(mutable_data.data(), mutable_data.size());
// Create disassembler. Early exit on failure.
auto disassembler_elf_x64 =
zucchini::Disassembler::Make<zucchini::DisassemblerElfX64>(image);
if (disassembler_elf_x64) {
zucchini::ReadAndWriteReferences(std::move(disassembler_elf_x64),
&mutable_data);
return 0;
}
auto disassembler_elf_x86 =
zucchini::Disassembler::Make<zucchini::DisassemblerElfX86>(image);
if (disassembler_elf_x86)
zucchini::ReadAndWriteReferences(std::move(disassembler_elf_x86),
&mutable_data);
return 0;
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "components/zucchini/buffer_view.h" #include "components/zucchini/buffer_view.h"
#include "components/zucchini/disassembler.h" #include "components/zucchini/disassembler.h"
#include "components/zucchini/disassembler_win32.h" #include "components/zucchini/disassembler_win32.h"
#include "components/zucchini/fuzzers/fuzz_utils.h"
namespace { namespace {
...@@ -22,33 +23,6 @@ struct Environment { ...@@ -22,33 +23,6 @@ struct Environment {
} }
}; };
// Helper function that uses |disassembler| to read all references from
// |mutable_image| and write them back.
void ReadAndWriteReferences(
std::unique_ptr<zucchini::Disassembler> disassembler,
std::vector<uint8_t>* mutable_data) {
zucchini::MutableBufferView mutable_image(mutable_data->data(),
disassembler->size());
std::vector<zucchini::Reference> references;
auto groups = disassembler->MakeReferenceGroups();
std::map<zucchini::PoolTag, std::vector<zucchini::Reference>>
references_of_pool;
for (const auto& group : groups) {
auto reader = group.GetReader(disassembler.get());
std::vector<zucchini::Reference>* refs =
&references_of_pool[group.pool_tag()];
for (auto ref = reader->GetNext(); ref.has_value();
ref = reader->GetNext()) {
refs->push_back(ref.value());
}
}
for (const auto& group : groups) {
auto writer = group.GetWriter(mutable_image, disassembler.get());
for (const auto& ref : references_of_pool[group.pool_tag()])
writer->PutNext(ref);
}
}
} // namespace } // namespace
// Entry point for LibFuzzer. // Entry point for LibFuzzer.
...@@ -64,13 +38,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -64,13 +38,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
auto disassembler_win32x86 = auto disassembler_win32x86 =
zucchini::Disassembler::Make<zucchini::DisassemblerWin32X86>(image); zucchini::Disassembler::Make<zucchini::DisassemblerWin32X86>(image);
if (disassembler_win32x86) { if (disassembler_win32x86) {
ReadAndWriteReferences(std::move(disassembler_win32x86), &mutable_data); zucchini::ReadAndWriteReferences(std::move(disassembler_win32x86),
&mutable_data);
return 0; return 0;
} }
auto disassembler_win32x64 = auto disassembler_win32x64 =
zucchini::Disassembler::Make<zucchini::DisassemblerWin32X64>(image); zucchini::Disassembler::Make<zucchini::DisassemblerWin32X64>(image);
if (disassembler_win32x64) if (disassembler_win32x64)
ReadAndWriteReferences(std::move(disassembler_win32x64), &mutable_data); zucchini::ReadAndWriteReferences(std::move(disassembler_win32x64),
&mutable_data);
return 0; return 0;
} }
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/zucchini/fuzzers/fuzz_utils.h"
#include <map>
#include <memory>
#include <vector>
#include "components/zucchini/disassembler.h"
namespace zucchini {
void ReadAndWriteReferences(
std::unique_ptr<zucchini::Disassembler> disassembler,
std::vector<uint8_t>* mutable_data) {
zucchini::MutableBufferView mutable_image(mutable_data->data(),
disassembler->size());
std::vector<zucchini::Reference> references;
auto groups = disassembler->MakeReferenceGroups();
std::map<zucchini::PoolTag, std::vector<zucchini::Reference>>
references_of_pool;
for (const auto& group : groups) {
auto reader = group.GetReader(disassembler.get());
std::vector<zucchini::Reference>* refs =
&references_of_pool[group.pool_tag()];
for (auto ref = reader->GetNext(); ref.has_value();
ref = reader->GetNext()) {
refs->push_back(ref.value());
}
}
for (const auto& group : groups) {
auto writer = group.GetWriter(mutable_image, disassembler.get());
for (const auto& ref : references_of_pool[group.pool_tag()])
writer->PutNext(ref);
}
}
} // namespace zucchini
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_ZUCCHINI_FUZZERS_FUZZ_UTILS_H_
#define COMPONENTS_ZUCCHINI_FUZZERS_FUZZ_UTILS_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "components/zucchini/disassembler.h"
namespace zucchini {
// Helper function that uses |disassembler| to read all references from
// |mutable_data| and write them back.
void ReadAndWriteReferences(
std::unique_ptr<zucchini::Disassembler> disassembler,
std::vector<uint8_t>* mutable_data);
} // namespace zucchini
#endif // COMPONENTS_ZUCCHINI_FUZZERS_FUZZ_UTILS_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment