| // 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 <fcntl.h> |
| #include <getopt.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zx/channel.h> |
| |
| #include <block-client/cpp/remote-block-device.h> |
| #include <digest/digest.h> |
| #include <fbl/unique_fd.h> |
| #include <fs/vfs.h> |
| |
| #include "corrupt_blob.h" |
| #include "fs_block_client.h" |
| |
| using block_client::BlockDevice; |
| using block_client::RemoteBlockDevice; |
| |
| namespace { |
| |
| constexpr char kUsage[] = R"( |
| Usage: blobfs-corrupt [ <options>* ] |
| |
| options: (-d|--device) DEVICE The path to the block device |
| (-m|--merkle) MERKLE The blob identity to corrupt |
| |
| Given the path to a blobfs block device and a merkle root, this tool corrupts the data contents |
| of the blob so that it cannot be read when blobfs is mounted. |
| |
| )"; |
| |
| zx_status_t Usage() { |
| fprintf(stderr, kUsage); |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| zx_status_t ProcessArgs(int argc, char** argv, zx::channel* block_channel, |
| BlobCorruptOptions* options) { |
| char* arg_block_path = nullptr; |
| char* arg_merkle = nullptr; |
| |
| while (1) { |
| static struct option opts[] = { |
| {"device", required_argument, nullptr, 'd'}, |
| {"merkle", required_argument, nullptr, 'm'}, |
| }; |
| |
| int opt_index; |
| int c = getopt_long(argc, argv, "d:m:", opts, &opt_index); |
| |
| if (c < 0) { |
| break; |
| } |
| |
| switch (c) { |
| case 'd': |
| arg_block_path = optarg; |
| break; |
| case 'm': |
| arg_merkle = optarg; |
| break; |
| default: |
| return Usage(); |
| } |
| } |
| |
| if (arg_block_path == nullptr) { |
| FX_LOGS(ERROR) << "'-d <device_path>' is required"; |
| return Usage(); |
| } |
| |
| if (arg_merkle == nullptr) { |
| FX_LOGS(ERROR) << "'-m <merkle>' is required"; |
| return Usage(); |
| } |
| |
| zx_status_t status = options->merkle.Parse(arg_merkle); |
| |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "invalid merkle root: '" << arg_merkle << "'"; |
| return Usage(); |
| } |
| |
| fbl::unique_fd block_fd(open(arg_block_path, O_RDWR)); |
| |
| if (!block_fd) { |
| FX_LOGS(ERROR) << "unable to open block device: '" << arg_block_path << "' " |
| << errno; |
| return Usage(); |
| } |
| |
| status = fdio_fd_transfer(block_fd.release(), block_channel->reset_and_get_address()); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "unable to open block device: " << status; |
| return Usage(); |
| } |
| |
| return ZX_OK; |
| } |
| |
| } // namespace |
| |
| int main(int argc, char** argv) { |
| BlobCorruptOptions options; |
| zx::channel block_connection; |
| zx_status_t status = ProcessArgs(argc, argv, &block_connection, &options); |
| if (status != ZX_OK) { |
| return -1; |
| } |
| |
| std::unique_ptr<RemoteBlockDevice> device; |
| status = RemoteBlockDevice::Create(std::move(block_connection), &device); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Could not initialize block device"; |
| return -1; |
| } |
| |
| status = CorruptBlob(std::move(device), &options); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Could not corrupt the requested blob. Failed with error " |
| << status; |
| return -1; |
| } |
| return 0; |
| } |