From: Eric Biggers <ebiggers@kernel.org>
To: linux-fscrypt@vger.kernel.org
Cc: linux-ext4@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
Theodore Ts'o <tytso@mit.edu>, Jaegeuk Kim <jaegeuk@kernel.org>,
Victor Hsieh <victorhsieh@google.com>
Subject: [fsverity-utils RFC PATCH 2/2] programs/fsverity: Add dump_metadata subcommand
Date: Fri, 15 Jan 2021 10:24:02 -0800 [thread overview]
Message-ID: <20210115182402.35691-3-ebiggers@kernel.org> (raw)
In-Reply-To: <20210115182402.35691-1-ebiggers@kernel.org>
From: Eric Biggers <ebiggers@google.com>
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.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
Makefile | 1 +
programs/cmd_dump_metadata.c | 167 +++++++++++++++++++++++++++++++++++
programs/fsverity.c | 6 ++
programs/fsverity.h | 6 ++
4 files changed, 180 insertions(+)
create mode 100644 programs/cmd_dump_metadata.c
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..9b249ba
--- /dev/null
+++ b/programs/cmd_dump_metadata.c
@@ -0,0 +1,167 @@
+// 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" };
+ /*
+ * FS_VERITY_METADATA_TYPE_MERKLE_TREE requires Merkle tree block
+ * alignment. Use a 64K buffer which should always be enough.
+ */
+ struct fsverity_read_metadata_arg arg = { .length = 65536 };
+ 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
@@ -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,
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[]);
--
2.30.0
WARNING: multiple messages have this Message-ID (diff)
From: Eric Biggers <ebiggers@kernel.org>
To: linux-fscrypt@vger.kernel.org
Cc: Jaegeuk Kim <jaegeuk@kernel.org>,
linux-ext4@vger.kernel.org, Theodore Ts'o <tytso@mit.edu>,
Victor Hsieh <victorhsieh@google.com>,
linux-f2fs-devel@lists.sourceforge.net
Subject: [f2fs-dev] [fsverity-utils RFC PATCH 2/2] programs/fsverity: Add dump_metadata subcommand
Date: Fri, 15 Jan 2021 10:24:02 -0800 [thread overview]
Message-ID: <20210115182402.35691-3-ebiggers@kernel.org> (raw)
In-Reply-To: <20210115182402.35691-1-ebiggers@kernel.org>
From: Eric Biggers <ebiggers@google.com>
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.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
Makefile | 1 +
programs/cmd_dump_metadata.c | 167 +++++++++++++++++++++++++++++++++++
programs/fsverity.c | 6 ++
programs/fsverity.h | 6 ++
4 files changed, 180 insertions(+)
create mode 100644 programs/cmd_dump_metadata.c
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..9b249ba
--- /dev/null
+++ b/programs/cmd_dump_metadata.c
@@ -0,0 +1,167 @@
+// 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" };
+ /*
+ * FS_VERITY_METADATA_TYPE_MERKLE_TREE requires Merkle tree block
+ * alignment. Use a 64K buffer which should always be enough.
+ */
+ struct fsverity_read_metadata_arg arg = { .length = 65536 };
+ 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
@@ -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,
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[]);
--
2.30.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
next prev parent reply other threads:[~2021-01-15 18:25 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-15 18:24 [fsverity-utils RFC PATCH 0/2] Add dump_metadata subcommand Eric Biggers
2021-01-15 18:24 ` [f2fs-dev] " Eric Biggers
2021-01-15 18:24 ` [fsverity-utils RFC PATCH 1/2] Upgrade to latest fsverity_uapi.h Eric Biggers
2021-01-15 18:24 ` [f2fs-dev] " Eric Biggers
2021-01-15 18:24 ` Eric Biggers [this message]
2021-01-15 18:24 ` [f2fs-dev] [fsverity-utils RFC PATCH 2/2] programs/fsverity: Add dump_metadata subcommand Eric Biggers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210115182402.35691-3-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=jaegeuk@kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-fscrypt@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=victorhsieh@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.