diff options
author | Calder Kitagawa <ckitagawa@google.com> | 2018-04-06 19:31:25 +0000 |
---|---|---|
committer | Edward Lesmes <ehmaldonado@google.com> | 2021-07-23 22:03:49 +0000 |
commit | 97b68bff47e939b997bdf9364794591efa77ea8f (patch) | |
tree | 429a4a289b20d739cb86f85d9d0d1d674a3d2f2f | |
parent | 9e74a61b87dd26ed0f39c41399aedcff279c3f85 (diff) | |
download | zucchini-97b68bff47e939b997bdf9364794591efa77ea8f.tar.gz |
[Zucchini] Add Win32 PE Disassembler Fuzzer
Fuzzes both the x86 and x64 versions of disassembler_win32.h including
reading the reference types:
- Reloc
- Abs32
- Rel32
The fuzzer runs at ~3000 exec/s which is acceptable based on the
fuzzing guide. More details:
https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/efficient_fuzzer.md#Seed-Corpus
Interesting results should appear here:
https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/clusterfuzz.md#Status-Links
The seed corpus consists of x64 and x86 libegl which is the smallest
binary file in the Windows release of Chrome. Since memory usage and
runtime increase significantly with seed size choosing small binaries
is key. The sha1 sums are listed and these are uploaded to:
https://pantheon.corp.google.com/storage/browser/clusterfuzz-corpus/libfuzzer
This achives ~81% line coverage of all associated files within
1 500 000 runs with no single test exceeding 5 seconds. The bulk of
the uncovered code is the reference writers which are not part of
disassembly.
A follow-up improvement would be to validate that the references
are within the correct region of the file (or at least within the
file) although I'm unclear this is necessary for relocs or calls to
dlls.
Change-Id: I4682f90c3c037cb7d87d21d7c351817e6158f59f
Reviewed-on: https://chromium-review.googlesource.com/996520
Commit-Queue: Calder Kitagawa <ckitagawa@google.com>
Reviewed-by: Samuel Huang <huangs@chromium.org>
Reviewed-by: Max Moroz <mmoroz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548901}
NOKEYCHECK=True
GitOrigin-RevId: a3d605e38f9387bbab6c4b30ab35926e6da0ace4
-rw-r--r-- | BUILD.gn | 14 | ||||
-rw-r--r-- | disassembler_win32_fuzzer.cc | 64 |
2 files changed, 78 insertions, 0 deletions
@@ -122,6 +122,20 @@ if (is_win) { } } +# To download the corpus for local fuzzing use: +# gsutil -m rsync \ +# gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_win32_fuzzer \ +# components/zucchini/testdata/disassembler_win32_fuzzer +fuzzer_test("zucchini_disassembler_win32_fuzzer") { + sources = [ + "disassembler_win32_fuzzer.cc", + ] + deps = [ + ":zucchini_lib", + "//base", + ] +} + fuzzer_test("zucchini_patch_fuzzer") { sources = [ "patch_fuzzer.cc", diff --git a/disassembler_win32_fuzzer.cc b/disassembler_win32_fuzzer.cc new file mode 100644 index 0000000..dbbd0e8 --- /dev/null +++ b/disassembler_win32_fuzzer.cc @@ -0,0 +1,64 @@ +// Copyright 2018 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_win32.h" + +struct Environment { + Environment() { + logging::SetMinLogLevel(3); // Disable console spamming. + } +}; + +Environment* env = new Environment(); + +// Entry point for LibFuzzer. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Prep data. + zucchini::ConstBufferView image(data, size); + + // One of x86 or x64 should return a non-nullptr if the data is valid. + + // Output will be a pointer to zucchini::DisassemblerWin32X86 if successful + // or nullptr otherwise. + auto disassembler_win32x86 = + zucchini::Disassembler::Make<zucchini::DisassemblerWin32X86>(image); + if (disassembler_win32x86 != nullptr) { + // Parse the Win32 PE file and ensure nothing bad occurs. + // TODO(ckitagawa): Actually validate that the output reference is within + // the image. + auto relocx86 = disassembler_win32x86->MakeReadRelocs(0, image.size()); + while (relocx86->GetNext().has_value()) { + } + auto abs32x86 = disassembler_win32x86->MakeReadAbs32(0, image.size()); + while (abs32x86->GetNext().has_value()) { + } + auto rel32x86 = disassembler_win32x86->MakeReadRel32(0, image.size()); + while (rel32x86->GetNext().has_value()) { + } + } + + // Output will be a pointer to zucchini::DisassemblerWin32X64 if successful + // or nullptr otherwise. + auto disassembler_win32x64 = + zucchini::Disassembler::Make<zucchini::DisassemblerWin32X64>(image); + if (disassembler_win32x64 != nullptr) { + // Parse the Win32 PE file and ensure nothing bad occurs. + auto relocx64 = disassembler_win32x64->MakeReadRelocs(0, image.size()); + while (relocx64->GetNext().has_value()) { + } + auto abs32x64 = disassembler_win32x64->MakeReadAbs32(0, image.size()); + while (abs32x64->GetNext().has_value()) { + } + auto rel32x64 = disassembler_win32x64->MakeReadRel32(0, image.size()); + while (rel32x64->GetNext().has_value()) { + } + } + return 0; +} |