From: Eric Biggers <ebiggers@kernel.org>
To: linux-fscrypt@vger.kernel.org
Cc: Victor Hsieh <victorhsieh@google.com>
Subject: [fsverity-utils PATCH 4/4] programs/fsverity: add --out-merkle-tree and --out-descriptor options
Date: Thu, 3 Jun 2021 12:58:12 -0700 [thread overview]
Message-ID: <20210603195812.50838-5-ebiggers@kernel.org> (raw)
In-Reply-To: <20210603195812.50838-1-ebiggers@kernel.org>
From: Eric Biggers <ebiggers@google.com>
Make 'fsverity digest' and 'fsverity sign' support writing the Merkle
tree and fs-verity descriptor to files, using new options
'--out-merkle-tree=FILE' and '--out-descriptor=FILE'.
Normally these new options aren't useful, but they can be needed in
cases where the fs-verity metadata needs to be consumed by something
other than one of the native Linux kernel implementations of fs-verity.
This is different from 'fsverity dump_metadata' in that
'fsverity dump_metadata' only works on a file with fs-verity enabled,
whereas these new options are for the userspace file digest computation.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
programs/cmd_digest.c | 7 +++-
programs/cmd_sign.c | 17 ++++++---
programs/fsverity.c | 88 ++++++++++++++++++++++++++++++++++++++++++-
programs/fsverity.h | 4 +-
4 files changed, 107 insertions(+), 9 deletions(-)
diff --git a/programs/cmd_digest.c b/programs/cmd_digest.c
index 1a3c769..fd9f4de 100644
--- a/programs/cmd_digest.c
+++ b/programs/cmd_digest.c
@@ -18,6 +18,8 @@ static const struct option longopts[] = {
{"hash-alg", required_argument, NULL, OPT_HASH_ALG},
{"block-size", required_argument, NULL, OPT_BLOCK_SIZE},
{"salt", required_argument, NULL, OPT_SALT},
+ {"out-merkle-tree", required_argument, NULL, OPT_OUT_MERKLE_TREE},
+ {"out-descriptor", required_argument, NULL, OPT_OUT_DESCRIPTOR},
{"compact", no_argument, NULL, OPT_COMPACT},
{"for-builtin-sig", no_argument, NULL, OPT_FOR_BUILTIN_SIG},
{NULL, 0, NULL, 0}
@@ -40,6 +42,8 @@ int fsverity_cmd_digest(const struct fsverity_command *cmd,
case OPT_HASH_ALG:
case OPT_BLOCK_SIZE:
case OPT_SALT:
+ case OPT_OUT_MERKLE_TREE:
+ case OPT_OUT_DESCRIPTOR:
if (!parse_tree_param(c, optarg, &tree_params))
goto out_usage;
break;
@@ -114,7 +118,8 @@ int fsverity_cmd_digest(const struct fsverity_command *cmd,
}
status = 0;
out:
- destroy_tree_params(&tree_params);
+ if (!destroy_tree_params(&tree_params) && status == 0)
+ status = 1;
return status;
out_err:
diff --git a/programs/cmd_sign.c b/programs/cmd_sign.c
index 47ba6a2..81a4ddc 100644
--- a/programs/cmd_sign.c
+++ b/programs/cmd_sign.c
@@ -27,11 +27,13 @@ static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
}
static const struct option longopts[] = {
- {"hash-alg", required_argument, NULL, OPT_HASH_ALG},
- {"block-size", required_argument, NULL, OPT_BLOCK_SIZE},
- {"salt", required_argument, NULL, OPT_SALT},
- {"key", required_argument, NULL, OPT_KEY},
- {"cert", required_argument, NULL, OPT_CERT},
+ {"hash-alg", required_argument, NULL, OPT_HASH_ALG},
+ {"block-size", required_argument, NULL, OPT_BLOCK_SIZE},
+ {"salt", required_argument, NULL, OPT_SALT},
+ {"out-merkle-tree", required_argument, NULL, OPT_OUT_MERKLE_TREE},
+ {"out-descriptor", required_argument, NULL, OPT_OUT_DESCRIPTOR},
+ {"key", required_argument, NULL, OPT_KEY},
+ {"cert", required_argument, NULL, OPT_CERT},
{NULL, 0, NULL, 0}
};
@@ -54,6 +56,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
case OPT_HASH_ALG:
case OPT_BLOCK_SIZE:
case OPT_SALT:
+ case OPT_OUT_MERKLE_TREE:
+ case OPT_OUT_DESCRIPTOR:
if (!parse_tree_param(c, optarg, &tree_params))
goto out_usage;
break;
@@ -117,7 +121,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
status = 0;
out:
filedes_close(&file);
- destroy_tree_params(&tree_params);
+ if (!destroy_tree_params(&tree_params) && status == 0)
+ status = 1;
free(digest);
free(sig);
return status;
diff --git a/programs/fsverity.c b/programs/fsverity.c
index 1168430..f6aff3a 100644
--- a/programs/fsverity.c
+++ b/programs/fsverity.c
@@ -11,6 +11,7 @@
#include "fsverity.h"
+#include <fcntl.h>
#include <limits.h>
static const struct fsverity_command {
@@ -27,6 +28,7 @@ static const struct fsverity_command {
.usage_str =
" fsverity digest FILE...\n"
" [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
+" [--out-merkle-tree=FILE] [--out-descriptor=FILE]\n"
" [--compact] [--for-builtin-sig]\n"
#ifndef _WIN32
}, {
@@ -58,6 +60,7 @@ static const struct fsverity_command {
.usage_str =
" fsverity sign FILE OUT_SIGFILE --key=KEYFILE\n"
" [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
+" [--out-merkle-tree=FILE] [--out-descriptor=FILE]\n"
" [--cert=CERTFILE]\n"
}
};
@@ -200,6 +203,74 @@ static bool parse_salt_option(const char *arg, u8 **salt_ptr,
return true;
}
+struct metadata_callback_ctx {
+ struct filedes merkle_tree_file;
+ struct filedes descriptor_file;
+ struct libfsverity_metadata_callbacks callbacks;
+};
+
+static int handle_merkle_tree_size(void *_ctx, u64 size)
+{
+ struct metadata_callback_ctx *ctx = _ctx;
+
+ if (!preallocate_file(&ctx->merkle_tree_file, size))
+ return -EIO;
+ return 0;
+}
+
+static int handle_merkle_tree_block(void *_ctx, const void *block, size_t size,
+ u64 offset)
+{
+ struct metadata_callback_ctx *ctx = _ctx;
+
+ if (!full_pwrite(&ctx->merkle_tree_file, block, size, offset))
+ return -EIO;
+ return 0;
+}
+
+static int handle_descriptor(void *_ctx, const void *descriptor, size_t size)
+{
+ struct metadata_callback_ctx *ctx = _ctx;
+
+ if (!full_write(&ctx->descriptor_file, descriptor, size))
+ return -EIO;
+ return 0;
+}
+
+static bool parse_out_metadata_option(int opt_char, const char *arg,
+ const struct libfsverity_metadata_callbacks **cbs)
+{
+ struct metadata_callback_ctx *ctx;
+ struct filedes *file;
+ const char *opt_name;
+
+ if (*cbs) {
+ ctx = (*cbs)->ctx;
+ } else {
+ ctx = xzalloc(sizeof(*ctx));
+ ctx->merkle_tree_file.fd = -1;
+ ctx->descriptor_file.fd = -1;
+ ctx->callbacks.ctx = ctx;
+ *cbs = &ctx->callbacks;
+ }
+
+ if (opt_char == OPT_OUT_MERKLE_TREE) {
+ file = &ctx->merkle_tree_file;
+ opt_name = "--out-merkle-tree";
+ ctx->callbacks.merkle_tree_size = handle_merkle_tree_size;
+ ctx->callbacks.merkle_tree_block = handle_merkle_tree_block;
+ } else {
+ file = &ctx->descriptor_file;
+ opt_name = "--out-descriptor";
+ ctx->callbacks.descriptor = handle_descriptor;
+ }
+ if (file->fd >= 0) {
+ error_msg("%s can only be specified once", opt_name);
+ return false;
+ }
+ return open_file(file, arg, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+}
+
bool parse_tree_param(int opt_char, const char *arg,
struct libfsverity_merkle_tree_params *params)
{
@@ -211,15 +282,30 @@ bool parse_tree_param(int opt_char, const char *arg,
case OPT_SALT:
return parse_salt_option(arg, (u8 **)¶ms->salt,
¶ms->salt_size);
+ case OPT_OUT_MERKLE_TREE:
+ case OPT_OUT_DESCRIPTOR:
+ return parse_out_metadata_option(opt_char, arg,
+ ¶ms->metadata_callbacks);
default:
ASSERT(0);
}
}
-void destroy_tree_params(struct libfsverity_merkle_tree_params *params)
+bool destroy_tree_params(struct libfsverity_merkle_tree_params *params)
{
+ bool ok = true;
+
free((u8 *)params->salt);
+ if (params->metadata_callbacks) {
+ struct metadata_callback_ctx *ctx =
+ params->metadata_callbacks->ctx;
+
+ ok &= filedes_close(&ctx->merkle_tree_file);
+ ok &= filedes_close(&ctx->descriptor_file);
+ free(ctx);
+ }
memset(params, 0, sizeof(*params));
+ return ok;
}
int main(int argc, char *argv[])
diff --git a/programs/fsverity.h b/programs/fsverity.h
index 9785013..fe24087 100644
--- a/programs/fsverity.h
+++ b/programs/fsverity.h
@@ -29,6 +29,8 @@ enum {
OPT_KEY,
OPT_LENGTH,
OPT_OFFSET,
+ OPT_OUT_DESCRIPTOR,
+ OPT_OUT_MERKLE_TREE,
OPT_SALT,
OPT_SIGNATURE,
};
@@ -59,6 +61,6 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
void usage(const struct fsverity_command *cmd, FILE *fp);
bool parse_tree_param(int opt_char, const char *arg,
struct libfsverity_merkle_tree_params *params);
-void destroy_tree_params(struct libfsverity_merkle_tree_params *params);
+bool destroy_tree_params(struct libfsverity_merkle_tree_params *params);
#endif /* PROGRAMS_FSVERITY_H */
--
2.31.1
next prev parent reply other threads:[~2021-06-03 20:00 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-03 19:58 [fsverity-utils PATCH 0/4] Add option to write Merkle tree to a file Eric Biggers
2021-06-03 19:58 ` [fsverity-utils PATCH 1/4] lib/compute_digest: add callbacks for getting the verity metadata Eric Biggers
2021-06-03 19:58 ` [fsverity-utils PATCH 2/4] programs/test_compute_digest: test the metadata callbacks Eric Biggers
2021-06-03 19:58 ` [fsverity-utils PATCH 3/4] programs/utils: add full_pwrite() and preallocate_file() Eric Biggers
2021-06-04 0:33 ` Victor Hsieh
2021-06-04 0:57 ` Eric Biggers
2021-06-04 15:24 ` Victor Hsieh
2021-06-04 16:55 ` Eric Biggers
2021-06-03 19:58 ` Eric Biggers [this message]
2021-06-04 15:25 ` [fsverity-utils PATCH 0/4] Add option to write Merkle tree to a file Victor Hsieh
2021-06-09 6:48 ` 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=20210603195812.50838-5-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=linux-fscrypt@vger.kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).