diff mbox series

[16/40] fsverity: pass the zero-hash value to the implementation

Message ID 171069246170.2684506.16175333193381403848.stgit@frogsfrogsfrogs (mailing list archive)
State Superseded
Headers show
Series [01/40] fsverity: remove hash page spin lock | expand

Commit Message

Darrick J. Wong March 17, 2024, 4:27 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Compute the hash of a data block full of zeros, and then supply this to
the merkle tree read and write methods.  A subsequent xfs patch will use
this to reduce the size of the merkle tree when dealing with sparse gold
master disk images and the like.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/verity/enable.c           |    2 ++
 fs/verity/fsverity_private.h |    2 ++
 fs/verity/open.c             |    7 +++++++
 fs/verity/verify.c           |    2 ++
 include/linux/fsverity.h     |    8 ++++++++
 5 files changed, 21 insertions(+)

Comments

Eric Biggers March 18, 2024, 4:38 p.m. UTC | #1
On Sun, Mar 17, 2024 at 09:27:34AM -0700, Darrick J. Wong wrote:
> diff --git a/fs/verity/open.c b/fs/verity/open.c
> index 7a86407732c4..433a70eeca55 100644
> --- a/fs/verity/open.c
> +++ b/fs/verity/open.c
> @@ -144,6 +144,13 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
>  		goto out_err;
>  	}
>  
> +	err = fsverity_hash_buffer(params->hash_alg, page_address(ZERO_PAGE(0)),
> +				   i_blocksize(inode), params->zero_digest);
> +	if (err) {
> +		fsverity_err(inode, "Error %d computing zero digest", err);
> +		goto out_err;
> +	}

This doesn't take the salt into account.  Also it's using the wrong block size
(filesystem block size instead of Merkle tree block size).

How about using fsverity_hash_block()?

- Eric
Darrick J. Wong March 18, 2024, 9:04 p.m. UTC | #2
On Mon, Mar 18, 2024 at 09:38:47AM -0700, Eric Biggers wrote:
> On Sun, Mar 17, 2024 at 09:27:34AM -0700, Darrick J. Wong wrote:
> > diff --git a/fs/verity/open.c b/fs/verity/open.c
> > index 7a86407732c4..433a70eeca55 100644
> > --- a/fs/verity/open.c
> > +++ b/fs/verity/open.c
> > @@ -144,6 +144,13 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
> >  		goto out_err;
> >  	}
> >  
> > +	err = fsverity_hash_buffer(params->hash_alg, page_address(ZERO_PAGE(0)),
> > +				   i_blocksize(inode), params->zero_digest);
> > +	if (err) {
> > +		fsverity_err(inode, "Error %d computing zero digest", err);
> > +		goto out_err;
> > +	}
> 
> This doesn't take the salt into account.  Also it's using the wrong block size
> (filesystem block size instead of Merkle tree block size).
> 
> How about using fsverity_hash_block()?

/me looks at build_merkle_tree again, realizes that it calls
hash_one_block on params->block_size bytes of file data.

IOWs, fsverity_hash_block is indeed the correct function to call here.
Thanks for the correction!

--D

> - Eric
diff mbox series

Patch

diff --git a/fs/verity/enable.c b/fs/verity/enable.c
index 8dcfefc848ee..06b769dd1bdf 100644
--- a/fs/verity/enable.c
+++ b/fs/verity/enable.c
@@ -52,6 +52,8 @@  static int write_merkle_tree_block(struct inode *inode, const u8 *buf,
 {
 	struct fsverity_writemerkle req = {
 		.inode = inode,
+		.zero_digest = params->zero_digest,
+		.digest_size = params->digest_size,
 	};
 	u64 pos = (u64)index << params->log_blocksize;
 	int err;
diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index de8798f141d4..195a92f203bb 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -47,6 +47,8 @@  struct merkle_tree_params {
 	u64 tree_size;			/* Merkle tree size in bytes */
 	unsigned long tree_pages;	/* Merkle tree size in pages */
 
+	u8 zero_digest[FS_VERITY_MAX_DIGEST_SIZE]; /* hash of zeroed data block */
+
 	/*
 	 * Starting block index for each tree level, ordered from leaf level (0)
 	 * to root level ('num_levels - 1')
diff --git a/fs/verity/open.c b/fs/verity/open.c
index 7a86407732c4..433a70eeca55 100644
--- a/fs/verity/open.c
+++ b/fs/verity/open.c
@@ -144,6 +144,13 @@  int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
 		goto out_err;
 	}
 
+	err = fsverity_hash_buffer(params->hash_alg, page_address(ZERO_PAGE(0)),
+				   i_blocksize(inode), params->zero_digest);
+	if (err) {
+		fsverity_err(inode, "Error %d computing zero digest", err);
+		goto out_err;
+	}
+
 	params->tree_size = offset << log_blocksize;
 	params->tree_pages = PAGE_ALIGN(params->tree_size) >> PAGE_SHIFT;
 	return 0;
diff --git a/fs/verity/verify.c b/fs/verity/verify.c
index a61d1c99c485..494225f60608 100644
--- a/fs/verity/verify.c
+++ b/fs/verity/verify.c
@@ -409,6 +409,8 @@  int fsverity_read_merkle_tree_block(struct inode *inode,
 			.num_levels = params->num_levels,
 			.log_blocksize = params->log_blocksize,
 			.ra_bytes = ra_bytes,
+			.zero_digest = params->zero_digest,
+			.digest_size = params->digest_size,
 		};
 		block->verified = false;
 
diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h
index 0dded1fcf2b1..da23f1e30151 100644
--- a/include/linux/fsverity.h
+++ b/include/linux/fsverity.h
@@ -66,6 +66,8 @@  struct fsverity_blockbuf {
  *		if the page at @block->offset isn't already cached.
  *		Implementations may ignore this argument; it's only a
  *		performance optimization.
+ * @zero_digest: the hash for a data block of zeroes
+ * @digest_size: size of zero_digest
  */
 struct fsverity_readmerkle {
 	struct inode *inode;
@@ -73,6 +75,8 @@  struct fsverity_readmerkle {
 	int level;
 	int num_levels;
 	u8 log_blocksize;
+	const u8 *zero_digest;
+	unsigned int digest_size;
 };
 
 /**
@@ -81,12 +85,16 @@  struct fsverity_readmerkle {
  * @level: level of the block; level 0 are the leaves
  * @num_levels: number of levels in the tree total
  * @log_blocksize: log2 of the size of the block
+ * @zero_digest: the hash for a data block of zeroes
+ * @digest_size: size of zero_digest
  */
 struct fsverity_writemerkle {
 	struct inode *inode;
 	int level;
 	int num_levels;
 	u8 log_blocksize;
+	const u8 *zero_digest;
+	unsigned int digest_size;
 };
 
 /* Verity operations for filesystems */