diff mbox series

[10/20] Change libfsverity_compute_digest() to take a read function

Message ID 20200424205504.2586682-11-Jes.Sorensen@gmail.com (mailing list archive)
State Superseded
Headers show
Series Split fsverity-utils into a shared library | expand

Commit Message

Jes Sorensen April 24, 2020, 8:54 p.m. UTC
From: Jes Sorensen <jsorensen@fb.com>

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@fb.com>
---
 cmd_sign.c    | 20 +++++++++++++++++++-
 libfsverity.h |  3 ++-
 libverity.c   | 39 +++++++--------------------------------
 3 files changed, 28 insertions(+), 34 deletions(-)
diff mbox series

Patch

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(&params, 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, &params, &digest))
+	if (libfsverity_compute_digest(&file, file_size, read_callback,
+				       &params, &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;