@@ -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);
@@ -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);
@@ -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;