aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2021-01-15 10:24:02 -0800
committerEric Biggers <ebiggers@google.com>2021-02-24 13:32:36 -0800
commitcf8fa5e5a7ac5b3b2dbfcc87e5dbd5f984c2d83a (patch)
tree56d88be04c7493ac37801b9fdfaae9f326dc18d5
parent1a7bc44a0b536de901f682337add379c1ebbf218 (diff)
downloadfsverity-utils-cf8fa5e5a7ac5b3b2dbfcc87e5dbd5f984c2d83a.tar.gz
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>
-rw-r--r--Makefile1
-rw-r--r--programs/cmd_dump_metadata.c163
-rw-r--r--programs/fsverity.c6
-rw-r--r--programs/fsverity.h6
4 files changed, 176 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 0354f62..fd28b06 100644
--- a/Makefile
+++ b/Makefile
@@ -160,6 +160,7 @@ FSVERITY_PROG_OBJ := $(PROG_COMMON_OBJ) \
programs/fsverity.o
ifneq ($(MINGW),1)
FSVERITY_PROG_OBJ += \
+ programs/cmd_dump_metadata.o \
programs/cmd_enable.o \
programs/cmd_measure.o
endif
diff --git a/programs/cmd_dump_metadata.c b/programs/cmd_dump_metadata.c
new file mode 100644
index 0000000..94cc8ec
--- /dev/null
+++ b/programs/cmd_dump_metadata.c
@@ -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;
+}
diff --git a/programs/fsverity.c b/programs/fsverity.c
index b911b2e..1168430 100644
--- a/programs/fsverity.c
+++ b/programs/fsverity.c
@@ -30,6 +30,12 @@ static const struct fsverity_command {
" [--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,
.short_desc = "Enable fs-verity on a file",
diff --git a/programs/fsverity.h b/programs/fsverity.h
index 45c4fe1..9785013 100644
--- a/programs/fsverity.h
+++ b/programs/fsverity.h
@@ -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[]);