mirror of
https://github.com/openharmony/third_party_fsverity-utils.git
synced 2026-07-01 10:05:35 -04:00
programs/fsverity: Add dump_metadata subcommand
Add a 'fsverity dump_metadata' subcommand which calls FS_IOC_READ_VERITY_METADATA on a file and prints the returned metadata to stdout. There are three subsubcommands, one for each type of metadata that can be read using the ioctl: fsverity dump_metadata merkle_tree FILE fsverity dump_metadata descriptor FILE fsverity dump_metadata signature FILE By default the whole metadata item is dumped. --length and --offset can be specified to dump only a particular range of the item. This subcommand will be used by xfstests to test the FS_IOC_READ_VERITY_METADATA ioctl. Link: https://lore.kernel.org/r/20210115182402.35691-3-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* The 'fsverity dump_metadata' command
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
#include "fsverity.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const struct option longopts[] = {
|
||||
{"offset", required_argument, NULL, OPT_OFFSET},
|
||||
{"length", required_argument, NULL, OPT_LENGTH},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
int val;
|
||||
} metadata_types[] = {
|
||||
{"merkle_tree", FS_VERITY_METADATA_TYPE_MERKLE_TREE},
|
||||
{"descriptor", FS_VERITY_METADATA_TYPE_DESCRIPTOR},
|
||||
{"signature", FS_VERITY_METADATA_TYPE_SIGNATURE},
|
||||
};
|
||||
|
||||
static bool parse_metadata_type(const char *name, __u64 *val_ret)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(metadata_types); i++) {
|
||||
if (strcmp(name, metadata_types[i].name) == 0) {
|
||||
*val_ret = metadata_types[i].val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
error_msg("unknown metadata type: %s", name);
|
||||
fputs(" Expected", stderr);
|
||||
for (i = 0; i < ARRAY_SIZE(metadata_types); i++) {
|
||||
if (i != 0 && ARRAY_SIZE(metadata_types) > 2)
|
||||
putc(',', stderr);
|
||||
putc(' ', stderr);
|
||||
if (i != 0 && i == ARRAY_SIZE(metadata_types) - 1)
|
||||
fputs("or ", stderr);
|
||||
fprintf(stderr, "\"%s\"", metadata_types[i].name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Dump the fs-verity metadata of the given file. */
|
||||
int fsverity_cmd_dump_metadata(const struct fsverity_command *cmd,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
bool offset_specified = false;
|
||||
bool length_specified = false;
|
||||
struct filedes file = { .fd = -1 };
|
||||
struct filedes stdout_filedes = { .fd = STDOUT_FILENO,
|
||||
.name = "stdout" };
|
||||
struct fsverity_read_metadata_arg arg = { .length = 32768 };
|
||||
void *buf = NULL;
|
||||
char *tmp;
|
||||
int c;
|
||||
int status;
|
||||
int bytes_read;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case OPT_OFFSET:
|
||||
if (offset_specified) {
|
||||
error_msg("--offset can only be specified once");
|
||||
goto out_usage;
|
||||
}
|
||||
errno = 0;
|
||||
arg.offset = strtoull(optarg, &tmp, 10);
|
||||
if (errno || *tmp) {
|
||||
error_msg("invalid value for --offset");
|
||||
goto out_usage;
|
||||
}
|
||||
offset_specified = true;
|
||||
break;
|
||||
case OPT_LENGTH:
|
||||
if (length_specified) {
|
||||
error_msg("--length can only be specified once");
|
||||
goto out_usage;
|
||||
}
|
||||
errno = 0;
|
||||
arg.length = strtoull(optarg, &tmp, 10);
|
||||
if (errno || *tmp || arg.length > SIZE_MAX) {
|
||||
error_msg("invalid value for --length");
|
||||
goto out_usage;
|
||||
}
|
||||
length_specified = true;
|
||||
break;
|
||||
default:
|
||||
goto out_usage;
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc != 2)
|
||||
goto out_usage;
|
||||
|
||||
if (!parse_metadata_type(argv[0], &arg.metadata_type))
|
||||
goto out_usage;
|
||||
|
||||
if (length_specified && !offset_specified) {
|
||||
error_msg("--length specified without --offset");
|
||||
goto out_usage;
|
||||
}
|
||||
if (offset_specified && !length_specified) {
|
||||
error_msg("--offset specified without --length");
|
||||
goto out_usage;
|
||||
}
|
||||
|
||||
buf = xzalloc(arg.length);
|
||||
arg.buf_ptr = (uintptr_t)buf;
|
||||
|
||||
if (!open_file(&file, argv[1], O_RDONLY, 0))
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* If --offset and --length were specified, then do only the single read
|
||||
* requested. Otherwise read until EOF.
|
||||
*/
|
||||
do {
|
||||
bytes_read = ioctl(file.fd, FS_IOC_READ_VERITY_METADATA, &arg);
|
||||
if (bytes_read < 0) {
|
||||
error_msg_errno("FS_IOC_READ_VERITY_METADATA failed on '%s'",
|
||||
file.name);
|
||||
goto out_err;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
if (!full_write(&stdout_filedes, buf, bytes_read))
|
||||
goto out_err;
|
||||
arg.offset += bytes_read;
|
||||
} while (!length_specified);
|
||||
|
||||
status = 0;
|
||||
out:
|
||||
free(buf);
|
||||
filedes_close(&file);
|
||||
return status;
|
||||
|
||||
out_err:
|
||||
status = 1;
|
||||
goto out;
|
||||
|
||||
out_usage:
|
||||
usage(cmd, stderr);
|
||||
status = 2;
|
||||
goto out;
|
||||
}
|
||||
@@ -29,6 +29,12 @@ static const struct fsverity_command {
|
||||
" [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
|
||||
" [--compact] [--for-builtin-sig]\n"
|
||||
#ifndef _WIN32
|
||||
}, {
|
||||
.name = "dump_metadata",
|
||||
.func = fsverity_cmd_dump_metadata,
|
||||
.short_desc = "Dump the fs-verity metadata of the given file",
|
||||
.usage_str =
|
||||
" fsverity dump_metadata TYPE FILE [--offset=OFFSET] [--length=LENGTH]\n"
|
||||
}, {
|
||||
.name = "enable",
|
||||
.func = fsverity_cmd_enable,
|
||||
|
||||
@@ -27,6 +27,8 @@ enum {
|
||||
OPT_FOR_BUILTIN_SIG,
|
||||
OPT_HASH_ALG,
|
||||
OPT_KEY,
|
||||
OPT_LENGTH,
|
||||
OPT_OFFSET,
|
||||
OPT_SALT,
|
||||
OPT_SIGNATURE,
|
||||
};
|
||||
@@ -37,6 +39,10 @@ struct fsverity_command;
|
||||
int fsverity_cmd_digest(const struct fsverity_command *cmd,
|
||||
int argc, char *argv[]);
|
||||
|
||||
/* cmd_dump_metadata.c */
|
||||
int fsverity_cmd_dump_metadata(const struct fsverity_command *cmd,
|
||||
int argc, char *argv[]);
|
||||
|
||||
/* cmd_enable.c */
|
||||
int fsverity_cmd_enable(const struct fsverity_command *cmd,
|
||||
int argc, char *argv[]);
|
||||
|
||||
Reference in New Issue
Block a user