| // Copyright 2021 The Chromium OS 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 <unistd.h> |
| #include <cinttypes> |
| |
| #include <base/check.h> |
| #include <base/files/file.h> |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/logging.h> |
| #include <base/strings/stringprintf.h> |
| #include <fuzzer/FuzzedDataProvider.h> |
| #include <session_manager/dbus-proxy-mocks.h> |
| |
| #include "crash-reporter/kernel_collector.h" |
| #include "crash-reporter/paths.h" |
| #include "crash-reporter/test_util.h" |
| |
| namespace { |
| |
| class Environment { |
| public: |
| Environment() { logging::SetMinLogLevel(logging::LOGGING_FATAL); } |
| }; |
| |
| class KernelCollectorForFuzzing : public KernelCollector { |
| public: |
| KernelCollectorForFuzzing() : KernelCollector() {} |
| |
| void SetUpDBus() override { |
| // Mock out all DBus calls so (a) we don't actually call DBus and (b) we |
| // don't CHECK fail when the DBus calls fail. |
| auto mock = |
| std::make_unique<org::chromium::SessionManagerInterfaceProxyMock>(); |
| test_util::SetActiveSessions(mock.get(), {}); |
| session_manager_proxy_ = std::move(mock); |
| } |
| |
| int Fuzz(FuzzedDataProvider* const data_provider) { |
| // Put all files into a per-run temp directory. |
| base::ScopedTempDir temp_dir; |
| CHECK(temp_dir.CreateUniqueTempDir()); |
| base::FilePath test_dir = temp_dir.GetPath(); |
| paths::SetPrefixForTesting(test_dir); |
| |
| auto kcrash_dir = test_dir.Append("kcrash"); |
| CHECK(base::CreateDirectory(kcrash_dir)); |
| |
| auto crash_directory = test_dir.Append("crash_directory"); |
| CHECK(base::CreateDirectory(crash_directory)); |
| |
| auto arch = data_provider->ConsumeEnum<kernel_util::ArchKind>(); |
| |
| auto eventlog = test_dir.Append("eventlog.txt"); |
| if (!WriteFuzzedFile(data_provider, eventlog)) |
| return 0; |
| |
| auto bios_log = test_dir.Append("bios_log"); |
| if (!WriteFuzzedFile(data_provider, bios_log)) |
| return 0; |
| |
| // Fuzz either a ramoops crash or EFI crash. |
| if (data_provider->ConsumeBool()) { |
| base::FilePath ramoops; |
| |
| if (data_provider->ConsumeBool()) { |
| ramoops = kcrash_dir.Append("console-ramoops-0"); |
| } else if (data_provider->ConsumeBool()) { |
| ramoops = kcrash_dir.Append("console-ramoops"); |
| } else { |
| ramoops = kcrash_dir.Append("dmesg-ramoops-0"); |
| } |
| if (!WriteFuzzedFile(data_provider, ramoops)) |
| return 0; |
| } else { |
| int maxEfiParts = data_provider->ConsumeIntegralInRange<int>( |
| 0, KernelCollector::EfiCrash::kMaxPart); |
| uint64_t id = data_provider->ConsumeIntegral<uint64_t>(); |
| |
| for (int i = 0; i < maxEfiParts; i++) { |
| auto efikcrash = kcrash_dir.Append(base::StringPrintf( |
| "dmesg-efi-%" PRIu64, |
| (id * maxEfiParts + i) * KernelCollector::EfiCrash::kMaxDumpRecord + |
| 1)); |
| if (!WriteFuzzedFile(data_provider, efikcrash)) |
| return 0; |
| } |
| } |
| |
| Initialize(false); |
| set_arch(arch); |
| |
| OverrideEventLogPath(eventlog); |
| OverrideBiosLogPath(bios_log); |
| OverridePreservedDumpPath(kcrash_dir); |
| |
| Collect(); |
| |
| return 0; |
| } |
| |
| private: |
| bool WriteFuzzedFile(FuzzedDataProvider* const data_provider, |
| const base::FilePath& file_path) { |
| constexpr int kArbitraryMaxFileLength = 1024 * 1024; |
| |
| auto path = base::FilePath(file_path); |
| base::File file(path, |
| base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); |
| if (!file.created()) { |
| LOG(ERROR) << "Failed to create " << file_path.value(); |
| return false; |
| } |
| |
| const std::string& file_contents = |
| data_provider->ConsumeRandomLengthString(kArbitraryMaxFileLength); |
| file.Write(0, file_contents.c_str(), file_contents.length()); |
| |
| return true; |
| } |
| }; |
| |
| } // namespace |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| static Environment env; |
| |
| FuzzedDataProvider data_provider(data, size); |
| KernelCollectorForFuzzing collector; |
| |
| return collector.Fuzz(&data_provider); |
| } |