blob: 44b96b30f73ed6d127a392204f1c3b73297e00d3 [file] [log] [blame]
// Copyright 2019 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 <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include <base/bind.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/time/time.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "crash-reporter/crash_sender_util.h"
#include "crash-reporter/paths.h"
#include "crash-reporter/test_util.h"
#include "metrics/metrics_library_mock.h"
namespace {
class Environment {
public:
Environment() {
// Disable logging per instructions.
logging::SetMinLogLevel(logging::LOGGING_FATAL);
// Don't ever actually upload anything!
util::g_force_is_mock = true;
}
};
// Ignore calls to sleep inside crash_sender.
void IgnoreSleep(base::TimeDelta duration) {}
// Creates a file with a random name and random contents. File will always be
// located in or below |test_dir|.
void CreateRandomFile(base::StringPiece suffix,
const base::FilePath& test_dir,
FuzzedDataProvider* provider) {
const int kArbitraryMaxFileNameLength = 50;
base::FilePath file_name(
provider->ConsumeRandomLengthString(kArbitraryMaxFileNameLength));
if (!suffix.empty()) {
file_name = file_name.AddExtension(suffix);
}
if (file_name.IsAbsolute()) {
return; // Or Append() will check-fail. Fuzzers should not exit.
}
base::FilePath file_path = test_dir.Append(file_name);
// Don't allow the fuzzer to write to random directories outside the
// test directory.
if (!test_dir.IsParent(file_path)) {
return;
}
const int kArbitraryMaxFileSize = 5000;
std::string content =
provider->ConsumeRandomLengthString(kArbitraryMaxFileSize);
base::CreateDirectory(file_path.DirName());
base::WriteFile(file_path, content.c_str(), content.length());
}
// Make the lock file. If we don't make the lock file's directory,
// AcquireLockFileOrDie() will fatal-error. If a fuzzer turns the lock file into
// a directory, we'll also die. Get in ahead of the fuzzer and make sure it's a
// normal file.
void MakeLockFile() {
base::FilePath lock_file_path = paths::Get(paths::kCrashSenderLockFile);
base::FilePath lock_file_dir = lock_file_path.DirName();
CHECK(base::CreateDirectory(lock_file_dir));
CHECK_GE(base::WriteFile(lock_file_path, "", 0), 0);
}
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static Environment env;
// 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);
MakeLockFile();
FuzzedDataProvider provider(data, size);
auto metrics_lib = std::make_unique<MetricsLibraryMock>();
bool always_write_uploads_log = provider.ConsumeBool();
metrics_lib->set_metrics_enabled(provider.ConsumeBool());
metrics_lib->set_guest_mode(provider.ConsumeBool());
bool allow_dev_sending = provider.ConsumeBool();
util::g_force_is_mock_successful = provider.ConsumeBool();
// Create the actual meta file.
CreateRandomFile(".meta", test_dir, &provider);
// Create some files that can be referenced by the meta as a payload and such.
for (int related_files = provider.ConsumeIntegralInRange(0, 5);
related_files > 0; --related_files) {
// Ignoring errors; if we get illegal names, we should just keep going.
CreateRandomFile("", test_dir, &provider);
}
util::Sender::Options options;
options.max_spread_time = base::TimeDelta();
options.hold_off_time = base::TimeDelta();
options.allow_dev_sending = allow_dev_sending;
options.always_write_uploads_log = always_write_uploads_log;
options.sleep_function = base::Bind(&IgnoreSleep);
// The remaining lines are basically a condensed version of crash_sender.cc's
// RunChildMain.
util::Sender sender(std::move(metrics_lib),
std::make_unique<test_util::AdvancingClock>(), options);
std::vector<util::MetaFile> reports_to_send;
util::RemoveOrphanedCrashFiles(test_dir);
sender.RemoveAndPickCrashFiles(test_dir, &reports_to_send);
util::SortReports(&reports_to_send);
sender.SendCrashes(reports_to_send);
return 0;
}