From: Jes Sorensen <jsorensen@xxxxxx> This changes the library to take a read_fn as callback and a pointer to an opaque file descriptor. This allows us to provide a custome read function for things like rpm which reads from an cpio archive instead of a file on disk. Signed-off-by: Jes Sorensen <jsorensen@xxxxxx> --- cmd_sign.c | 20 +++++++++++++++++++- libfsverity.h | 3 ++- libverity.c | 39 +++++++-------------------------------- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/cmd_sign.c b/cmd_sign.c index e48e0aa..15d0937 100644 --- a/cmd_sign.c +++ b/cmd_sign.c @@ -12,6 +12,7 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include "commands.h" #include "libfsverity.h" @@ -45,6 +46,16 @@ static const struct option longopts[] = { {NULL, 0, NULL, 0} }; +static int read_callback(void *opague, void *buf, size_t count) +{ + int retval = -EBADF; + + if (full_read(opague, buf, count)) + retval = 0; + + return retval; +} + /* Sign a file for fs-verity by computing its measurement, then signing it. */ int fsverity_cmd_sign(const struct fsverity_command *cmd, int argc, char *argv[]) @@ -59,6 +70,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd, struct libfsverity_digest *digest = NULL; struct libfsverity_merkle_tree_params params; struct libfsverity_signature_params sig_params; + u64 file_size; char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1]; u8 *sig = NULL; size_t sig_size; @@ -131,6 +143,11 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd, if (!open_file(&file, argv[0], O_RDONLY, 0)) goto out_err; + if (!get_file_size(&file, &file_size)) { + error_msg_errno("unable to get file size"); + goto out_err; + } + memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); params.version = 1; params.hash_algorithm = hash_alg->hash_num; @@ -138,7 +155,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd, params.salt_size = salt_size; params.salt = salt; - if (libfsverity_compute_digest(file.fd, ¶ms, &digest)) + if (libfsverity_compute_digest(&file, file_size, read_callback, + ¶ms, &digest)) goto out_err; filedes_close(&file); diff --git a/libfsverity.h b/libfsverity.h index f6c4b13..ea36b8e 100644 --- a/libfsverity.h +++ b/libfsverity.h @@ -79,7 +79,8 @@ struct fsverity_hash_alg { * * digest_ret returns a pointer to the digest on success. */ int -libfsverity_compute_digest(int fd, +libfsverity_compute_digest(void *fd, size_t file_size, + int (*read_fn)(void *, void *buf, size_t count), const struct libfsverity_merkle_tree_params *params, struct libfsverity_digest **digest_ret); diff --git a/libverity.c b/libverity.c index e16306d..f82f2d6 100644 --- a/libverity.c +++ b/libverity.c @@ -50,30 +50,13 @@ static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur, return next->filled + hash->alg->digest_size > block_size; } -static int full_read_fd(int fd, void *buf, size_t count) -{ - while (count) { - int n = read(fd, buf, min(count, INT_MAX)); - - if (n < 0) { - error_msg_errno("reading from file"); - return n; - } - if (n == 0) { - error_msg("unexpected end-of-file"); - return -ENODATA; - } - buf += n; - count -= n; - } - return 0; -} - /* * Compute the file's Merkle tree root hash using the given hash algorithm, * block size, and salt. */ -static bool compute_root_hash(int fd, u64 file_size, +static bool compute_root_hash(void *fd, + int (*read_fn)(void *, void *buf, size_t count), + u64 file_size, struct hash_ctx *hash, u32 block_size, const u8 *salt, u32 salt_size, u8 *root_hash) { @@ -111,7 +94,7 @@ static bool compute_root_hash(int fd, u64 file_size, for (offset = 0; offset < file_size; offset += block_size) { buffers[-1].filled = min(block_size, file_size - offset); - if (full_read_fd(fd, buffers[-1].data, buffers[-1].filled)) + if (read_fn(fd, buffers[-1].data, buffers[-1].filled)) goto out; level = -1; @@ -145,7 +128,8 @@ out: * contains the Merkle tree properties including the root hash. */ int -libfsverity_compute_digest(int fd, +libfsverity_compute_digest(void *fd, size_t file_size, + int (*read_fn)(void *, void *buf, size_t count), const struct libfsverity_merkle_tree_params *params, struct libfsverity_digest **digest_ret) { @@ -153,8 +137,6 @@ libfsverity_compute_digest(int fd, struct libfsverity_digest *digest; struct hash_ctx *hash; struct fsverity_descriptor desc; - struct stat stbuf; - u64 file_size; int i, retval = -EINVAL; if (!digest_ret) @@ -191,13 +173,6 @@ libfsverity_compute_digest(int fd, digest->digest_size = cpu_to_le16(hash_alg->digest_size); memset(digest->digest, 0, hash_alg->digest_size); - if (fstat(fd, &stbuf) != 0) { - error_msg_errno("can't stat input file"); - retval = -EBADF; - goto error_out; - } - file_size = stbuf.st_size; - memset(&desc, 0, sizeof(desc)); desc.version = 1; desc.hash_algorithm = params->hash_algorithm; @@ -213,7 +188,7 @@ libfsverity_compute_digest(int fd, /* Root hash of empty file is all 0's */ if (file_size != 0 && - !compute_root_hash(fd, file_size, hash, params->block_size, + !compute_root_hash(fd, read_fn, file_size, hash, params->block_size, params->salt, params->salt_size, desc.root_hash)) { retval = -EAGAIN; -- 2.25.3