blob: de53cb32b0588be91a83619ec639c40b021eaf2c [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 <block-client/cpp/fake-device.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "src/storage/minfs/minfs_private.h"
namespace minfs {
namespace {
using ::block_client::FakeBlockDevice;
enum class Operation {
kFinished, // Must be first to ensure each case finishes.
kCreate,
kRead,
kWrite,
kMaxValue = kWrite
};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static Minfs& fs = []() -> Minfs& {
constexpr uint64_t kBlockCount = 1 << 17;
auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kMinfsBlockSize);
std::unique_ptr<Bcache> bcache;
ZX_ASSERT(Bcache::Create(std::move(device), kBlockCount, &bcache) == ZX_OK);
ZX_ASSERT(Mkfs(bcache.get()) == ZX_OK);
MountOptions options = {};
std::unique_ptr<Minfs> fs;
ZX_ASSERT(Minfs::Create(std::move(bcache), options, &fs) == ZX_OK);
return *fs.release();
}();
fbl::RefPtr<VnodeMinfs> root;
ZX_ASSERT(fs.VnodeGet(&root, kMinfsRootIno) == ZX_OK);
std::array<fbl::RefPtr<VnodeMinfs>, 10> files;
int open_files = 0;
void* buffer = std::malloc(65536);
std::vector<std::string> created_files;
FuzzedDataProvider fuzzed_data(data, size);
for (;;) {
auto operation = fuzzed_data.ConsumeEnum<Operation>();
switch (operation) {
case Operation::kFinished: {
for (auto& file : files) {
if (file) {
file->Close();
file = nullptr;
}
}
free(buffer);
for (auto& name : created_files) {
ZX_ASSERT(root->Unlink(name, /*must_be_dir=*/false) == ZX_OK);
}
ZX_ASSERT(fs.Info().alloc_block_count == 2);
ZX_ASSERT(fs.Info().alloc_inode_count == 2);
return 0;
}
case Operation::kCreate: {
int index = fuzzed_data.ConsumeIntegralInRange<int>(0, files.size() - 1);
std::string name = fuzzed_data.ConsumeRandomLengthString(NAME_MAX + 2);
uint32_t mode = fuzzed_data.ConsumeIntegral<uint32_t>();
if (files[index])
--open_files;
fbl::RefPtr<fs::Vnode> vnode;
zx_status_t status = root->Create(name, mode, &vnode);
if (status == ZX_OK) {
created_files.push_back(std::move(name));
if (files[index]) {
files[index]->Close();
} else {
++open_files;
}
files[index] = fbl::RefPtr<VnodeMinfs>::Downcast(std::move(vnode));
}
break;
}
case Operation::kRead: {
if (open_files == 0)
break;
int index = fuzzed_data.ConsumeIntegralInRange<uint8_t>(0, open_files - 1);
size_t read_len = fuzzed_data.ConsumeIntegralInRange<size_t>(0, 65536);
size_t offset = fuzzed_data.ConsumeIntegral<size_t>();
for (auto& file : files) {
if (file && --index <= 0) {
file->Read(buffer, read_len, offset, &read_len);
break;
}
}
break;
}
case Operation::kWrite: {
if (open_files == 0)
break;
int index = fuzzed_data.ConsumeIntegralInRange<uint8_t>(0, open_files - 1);
size_t write_len = fuzzed_data.ConsumeIntegralInRange<size_t>(0, 65536);
size_t offset = fuzzed_data.ConsumeIntegral<size_t>();
for (auto& file : files) {
if (file && --index <= 0) {
file->Write(buffer, write_len, offset, &write_len);
break;
}
}
break;
}
}
} // for (;;)
}
} // namespace
} // namespace minfs