Linux-XFS Archive mirror
 help / color / mirror / Atom feed
From: Eric Biggers <ebiggers@kernel.org>
To: "Darrick J. Wong" <djwong@kernel.org>
Cc: aalbersh@redhat.com, linux-xfs@vger.kernel.org,
	linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev
Subject: Re: [PATCH 03/13] fsverity: support block-based Merkle tree caching
Date: Thu, 4 Apr 2024 22:31:45 -0400	[thread overview]
Message-ID: <20240405023145.GB1958@quark.localdomain> (raw)
In-Reply-To: <171175867913.1987804.4275409634176359386.stgit@frogsfrogsfrogs>

On Fri, Mar 29, 2024 at 05:33:27PM -0700, Darrick J. Wong wrote:
> diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
> index b3506f56e180b..c9d97c2bebd84 100644
> --- a/fs/verity/fsverity_private.h
> +++ b/fs/verity/fsverity_private.h
> @@ -154,4 +154,41 @@ static inline void fsverity_init_signature(void)
>  
>  void __init fsverity_init_workqueue(void);
>  
> +static inline bool fsverity_caches_blocks(const struct inode *inode)
> +{
> +	const struct fsverity_operations *vops = inode->i_sb->s_vop;
> +
> +	WARN_ON_ONCE(vops->read_merkle_tree_block &&
> +		     !vops->drop_merkle_tree_block);
> +
> +	return vops->read_merkle_tree_block != NULL;
> +}
> +
> +static inline bool fsverity_uses_bitmap(const struct fsverity_info *vi,
> +					const struct inode *inode)
> +{
> +	if (fsverity_caches_blocks(inode))
> +		return false;
> +
> +	/*
> +	 * If fs uses block-based Merkle tree caching, then fs-verity must use
> +	 * hash_block_verified bitmap as there's no page to mark it with
> +	 * PG_checked.
> +	 */
> +	return vi->tree_params.block_size != PAGE_SIZE;
> +}

For checking whether the bitmap is in use, it's simpler and more efficient to
just directly check whether vi->hash_block_verified is NULL, as the existing
code does.  Only the code that allocates the bitmap actually needs to be aware
of the details of when the bitmap gets enabled.

fsverity_caches_blocks() has a similar issue, where it could just be replaced
with checking vops->read_merkle_tree_block != NULL directly (or equivalently
vops->drop_merkle_tree_block, which works well in
fsverity_drop_merkle_tree_block() since that's the function pointer it's
calling).  The WARN_ON_ONCE() should be done in fsverity_create_info(), not
inlined multiple times into the verification code.

(I think the name "fsverity_caches_blocks()" is also confusing because the
fsverity support layer does not cache blocks, but all the filesystems do.  What
it's actually trying to convey is a difference in how the filesystem caches the
blocks, which I don't think it does a good job at.)

> +int fsverity_read_merkle_tree_block(struct inode *inode,
> +				    const struct merkle_tree_params *params,
> +				    u64 pos, unsigned long ra_bytes,
> +				    struct fsverity_blockbuf *block);
> +
> +/*
> + * Drop 'block' obtained with ->read_merkle_tree_block(). Calls out back to
> + * filesystem if ->drop_merkle_tree_block() is set, otherwise, drop the
> + * reference in the block->context.

"drop the reference" => "drops the reference"

> +	/*
> +	 * If fs uses block-based Merkle tree cachin, then fs-verity must use
> +	 * hash_block_verified bitmap as there's no page to mark it with
> +	 * PG_checked.
> +	 */
> +	if (fsverity_uses_bitmap(vi, inode)) {

The comment contradicts the code.

> diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c
> index f58432772d9ea..94fffa060f829 100644
> --- a/fs/verity/read_metadata.c
> +++ b/fs/verity/read_metadata.c
> @@ -14,65 +14,60 @@
>  
>  static int fsverity_read_merkle_tree(struct inode *inode,
>  				     const struct fsverity_info *vi,
> -				     void __user *buf, u64 offset, int length)
> +				     void __user *buf, u64 pos, int length)
>  {
> -	const struct fsverity_operations *vops = inode->i_sb->s_vop;
> -	u64 end_offset;
> -	unsigned int offs_in_page;
> -	pgoff_t index, last_index;
> +	const u64 end_pos = min(pos + length, vi->tree_params.tree_size);
> +	const struct merkle_tree_params *params = &vi->tree_params;
> +	unsigned int offs_in_block = pos & (params->block_size - 1);
>  	int retval = 0;
>  	int err = 0;
>  
> -	end_offset = min(offset + length, vi->tree_params.tree_size);
> -	if (offset >= end_offset)
> +	if (pos >= end_pos)
>  		return 0;

The above 'pos >= end_pos' check is no longer necessary.

>  	/*
> -	 * Iterate through each Merkle tree page in the requested range and copy
> -	 * the requested portion to userspace.  Note that the Merkle tree block
> -	 * size isn't important here, as we are returning a byte stream; i.e.,
> -	 * we can just work with pages even if the tree block size != PAGE_SIZE.
> +	 * Iterate through each Merkle tree block in the requested range and
> +	 * copy the requested portion to userspace. Note that we are returning
> +	 * a byte stream.
>  	 */
> -	for (index = offset >> PAGE_SHIFT; index <= last_index; index++) {
> -		unsigned long num_ra_pages =
> -			min_t(unsigned long, last_index - index + 1,
> -			      inode->i_sb->s_bdi->io_pages);
> -		unsigned int bytes_to_copy = min_t(u64, end_offset - offset,
> -						   PAGE_SIZE - offs_in_page);
> -		struct page *page;
> -		const void *virt;
> +	while (pos < end_pos) {
> +		unsigned long ra_bytes;
> +		unsigned int bytes_to_copy;
> +		struct fsverity_blockbuf block = {
> +			.size = params->block_size,
> +		};
>  
> -		page = vops->read_merkle_tree_page(inode, index, num_ra_pages);
> -		if (IS_ERR(page)) {
> -			err = PTR_ERR(page);
> +		ra_bytes = min_t(unsigned long, end_pos - pos + 1,
> +				 inode->i_sb->s_bdi->io_pages << PAGE_SHIFT);

This introduces an off-by-one error in the calculation of ra_bytes.  end_pos
is exclusive, but the calculation of ra_bytes assumes it is inclusive.

Also, might io_pages << PAGE_SHIFT overflow an unsigned long?

> +		bytes_to_copy = min_t(u64, end_pos - pos,
> +				      params->block_size - offs_in_block);
> +
> +		err = fsverity_read_merkle_tree_block(inode, &vi->tree_params,
> +				pos - offs_in_block, ra_bytes, &block);
> +		if (err) {
>  			fsverity_err(inode,
> -				     "Error %d reading Merkle tree page %lu",
> -				     err, index);
> +				     "Error %d reading Merkle tree block %llu",
> +				     err, pos);
>  			break;

The error message should go into fsverity_read_merkle_tree_block() so that it
does not need to be duplicated in its two callers.  This would, additionally,
eliminate the need to introduce the 'err' variable in verify_data_block().

> diff --git a/fs/verity/verify.c b/fs/verity/verify.c
> index 4fcad0825a120..0b5e11073e883 100644
> --- a/fs/verity/verify.c
> +++ b/fs/verity/verify.c
> @@ -13,14 +13,27 @@
>  static struct workqueue_struct *fsverity_read_workqueue;
>  
>  /*
> - * Returns true if the hash block with index @hblock_idx in the tree, located in
> - * @hpage, has already been verified.
> + * Returns true if the hash block with index @hblock_idx in the tree has
> + * already been verified.
>   */
> -static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,
> +static bool is_hash_block_verified(struct inode *inode,
> +				   struct fsverity_blockbuf *block,
>  				   unsigned long hblock_idx)

The comment should be updated to mention @block.

> @@ -143,11 +156,9 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
>  	for (level = 0; level < params->num_levels; level++) {
>  		unsigned long next_hidx;
>  		unsigned long hblock_idx;
> -		pgoff_t hpage_idx;
> -		unsigned int hblock_offset_in_page;
> +		u64 hblock_pos;
>  		unsigned int hoffset;
> -		struct page *hpage;
> -		const void *haddr;
> +		struct fsverity_blockbuf *block = &hblocks[level].block;
>  
>  		/*
>  		 * The index of the block in the current level; also the index
> @@ -158,36 +169,34 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
>  		/* Index of the hash block in the tree overall */
>  		hblock_idx = params->level_start[level] + next_hidx;
>  
> -		/* Index of the hash page in the tree overall */
> -		hpage_idx = hblock_idx >> params->log_blocks_per_page;
> -
> -		/* Byte offset of the hash block within the page */
> -		hblock_offset_in_page =
> -			(hblock_idx << params->log_blocksize) & ~PAGE_MASK;
> +		/* Byte offset of the hash block in the tree overall */
> +		hblock_pos = hblock_idx << params->log_blocksize;

'hblock_idx << params->log_blocksize' may overflow an unsigned long, so
'hblock_idx' needs to be cast to u64 before doing the shift.

> +		if (level == 0)
> +			ra_bytes = min(max_ra_bytes,
> +				       params->tree_size - hblock_pos);
> +		else
> +			ra_bytes = 0;

The first argument to min() has type unsigned long, and the second has type u64.
Doesn't this generate a warning on 32-bit systems?

> @@ -325,7 +333,7 @@ void fsverity_verify_bio(struct bio *bio)
>  
>  	bio_for_each_folio_all(fi, bio) {
>  		if (!verify_data_blocks(fi.folio, fi.length, fi.offset,
> -					max_ra_pages)) {
> +					max_ra_pages << PAGE_SHIFT)) {
>  			bio->bi_status = BLK_STS_IOERR;
>  			break;

This function should calculate max_ra_bytes as bio->bi_iter.bi_size >> 2.  It's
not necessary to convert to pages, then back to bytes again.

> +/**
> + * fsverity_read_merkle_tree_block() - read Merkle tree block
> + * @inode: inode to which this Merkle tree blocks belong

"this Merkle tree blocks belong" => "this Merkle tree block belongs"

> + * @params: merkle tree parameters
> + * @pos: byte position within merkle tree
> + * @ra_bytes: try to read ahead this many btes

"btes" => "bytes"

> +int fsverity_read_merkle_tree_block(struct inode *inode,
> +				    const struct merkle_tree_params *params,
> +				    u64 pos, unsigned long ra_bytes,
> +				    struct fsverity_blockbuf *block)
> +{
> +	const struct fsverity_operations *vops = inode->i_sb->s_vop;
> +	unsigned long page_idx;
> +	struct page *page;
> +	unsigned long index;
> +	unsigned int offset_in_page;
> +
> +	if (fsverity_caches_blocks(inode)) {
> +		block->verified = false;
> +		return vops->read_merkle_tree_block(inode, pos, ra_bytes,
> +				params->log_blocksize, block);
> +	}
> +
> +	index = pos >> params->log_blocksize;

Should the fourth parameter to ->read_merkle_tree_block be the block index
(which is computed above) instead of log_blocksize?  XFS only uses
params->log_blocksize to compute the block index anyway.

> +/**
> + * struct fsverity_blockbuf - Merkle Tree block buffer
> + * @kaddr: virtual address of the block's data
> + * @offset: block's offset into Merkle tree
> + * @size: the Merkle tree block size
> + * @context: filesystem private context
> + * @verified: has this buffer been validated?
> + *
> + * Buffer containing single Merkle Tree block. These buffers are passed
> + *  - to filesystem, when fs-verity is building merkel tree,
> + *  - from filesystem, when fs-verity is reading merkle tree from a disk.
> + * Filesystems sets kaddr together with size to point to a memory which contains
> + * Merkle tree block. Same is done by fs-verity when Merkle tree is need to be
> + * written down to disk.

This comment still incorrectly claims that fsverity_blockbuf is being used for
writes.

- Eric

  reply	other threads:[~2024-04-05  2:31 UTC|newest]

Thread overview: 111+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-30  0:30 [PATCHBOMB v5.5] fs-verity support for XFS Darrick J. Wong
2024-03-30  0:32 ` [PATCHSET v5.5 1/2] fs-verity: support merkle tree access by blocks Darrick J. Wong
2024-03-30  0:32   ` [PATCH 01/13] fs: add FS_XFLAG_VERITY for verity files Darrick J. Wong
2024-03-30  0:33   ` [PATCH 02/13] fsverity: pass tree_blocksize to end_enable_verity() Darrick J. Wong
2024-03-30  0:33   ` [PATCH 03/13] fsverity: support block-based Merkle tree caching Darrick J. Wong
2024-04-05  2:31     ` Eric Biggers [this message]
2024-04-24 21:25       ` Darrick J. Wong
2024-04-24 22:08         ` Eric Biggers
2024-04-25  0:27           ` Darrick J. Wong
2024-04-25  0:46             ` Eric Biggers
2024-04-25  0:53               ` Darrick J. Wong
2024-03-30  0:33   ` [PATCH 04/13] fsverity: add per-sb workqueue for post read processing Darrick J. Wong
2024-04-05  2:39     ` Eric Biggers
2024-04-24 21:33       ` Darrick J. Wong
2024-03-30  0:33   ` [PATCH 05/13] fsverity: add tracepoints Darrick J. Wong
2024-03-30  0:34   ` [PATCH 06/13] fsverity: send the level of the merkle tree block to ->read_merkle_tree_block Darrick J. Wong
2024-04-05  2:42     ` Eric Biggers
2024-04-25  0:30       ` Darrick J. Wong
2024-03-30  0:34   ` [PATCH 07/13] fsverity: pass the new tree size and block size to ->begin_enable_verity Darrick J. Wong
2024-04-05  2:46     ` Eric Biggers
2024-04-24 21:36       ` Darrick J. Wong
2024-03-30  0:34   ` [PATCH 08/13] fsverity: expose merkle tree geometry to callers Darrick J. Wong
2024-04-05  2:50     ` Eric Biggers
2024-04-25  0:45       ` Darrick J. Wong
2024-04-25  0:49         ` Eric Biggers
2024-04-25  1:01           ` Darrick J. Wong
2024-04-25  1:04             ` Eric Biggers
2024-03-30  0:35   ` [PATCH 09/13] fsverity: box up the write_merkle_tree_block parameters too Darrick J. Wong
2024-04-05  2:52     ` Eric Biggers
2024-04-25  0:46       ` Darrick J. Wong
2024-03-30  0:35   ` [PATCH 10/13] fsverity: pass the zero-hash value to the implementation Darrick J. Wong
2024-04-05  2:57     ` Eric Biggers
2024-04-24 19:02       ` Darrick J. Wong
2024-04-24 19:19         ` Eric Biggers
2024-04-24 20:23           ` Darrick J. Wong
2024-04-24 20:59             ` Eric Biggers
2024-04-24 21:43               ` Darrick J. Wong
2024-03-30  0:35   ` [PATCH 11/13] fsverity: report validation errors back to the filesystem Darrick J. Wong
2024-04-05  3:09     ` Eric Biggers
2024-04-24 18:18       ` Darrick J. Wong
2024-04-24 18:52         ` Eric Biggers
2024-04-24 19:03           ` Darrick J. Wong
2024-03-30  0:35   ` [PATCH 12/13] fsverity: remove system-wide workqueue Darrick J. Wong
2024-04-05  3:14     ` Eric Biggers
2024-04-24 18:05       ` Darrick J. Wong
2024-04-24 18:41         ` Eric Biggers
2024-04-29 10:15         ` Andrey Albershteyn
2024-04-29 16:35           ` Darrick J. Wong
2024-03-30  0:36   ` [PATCH 13/13] iomap: integrate fs-verity verification into iomap's read path Darrick J. Wong
2024-03-30  0:32 ` [PATCHSET v5.5 2/2] xfs: fs-verity support Darrick J. Wong
2024-03-30  0:36   ` [PATCH 01/29] xfs: use unsigned ints for non-negative quantities in xfs_attr_remote.c Darrick J. Wong
2024-04-02  9:51     ` Andrey Albershteyn
2024-04-02 16:25       ` Darrick J. Wong
2024-03-30  0:36   ` [PATCH 02/29] xfs: turn XFS_ATTR3_RMT_BUF_SPACE into a function Darrick J. Wong
2024-04-02 10:09     ` Andrey Albershteyn
2024-03-30  0:36   ` [PATCH 03/29] xfs: create a helper to compute the blockcount of a max sized remote value Darrick J. Wong
2024-04-02 10:09     ` Andrey Albershteyn
2024-03-30  0:37   ` [PATCH 04/29] xfs: minor cleanups of xfs_attr3_rmt_blocks Darrick J. Wong
2024-04-02 10:11     ` Andrey Albershteyn
2024-03-30  0:37   ` [PATCH 05/29] xfs: add attribute type for fs-verity Darrick J. Wong
2024-03-30  0:37   ` [PATCH 06/29] xfs: do not use xfs_attr3_rmt_hdr for remote verity value blocks Darrick J. Wong
2024-03-30  0:37   ` [PATCH 07/29] xfs: add fs-verity ro-compat flag Darrick J. Wong
2024-03-30  0:38   ` [PATCH 08/29] xfs: add inode on-disk VERITY flag Darrick J. Wong
2024-03-30  0:38   ` [PATCH 09/29] xfs: initialize fs-verity on file open and cleanup on inode destruction Darrick J. Wong
2024-03-30  0:38   ` [PATCH 10/29] xfs: don't allow to enable DAX on fs-verity sealed inode Darrick J. Wong
2024-03-30  0:38   ` [PATCH 11/29] xfs: disable direct read path for fs-verity files Darrick J. Wong
2024-03-30  0:39   ` [PATCH 12/29] xfs: widen flags argument to the xfs_iflags_* helpers Darrick J. Wong
2024-04-02 12:37     ` Andrey Albershteyn
2024-04-02 16:27       ` Darrick J. Wong
2024-03-30  0:39   ` [PATCH 13/29] xfs: add fs-verity support Darrick J. Wong
2024-04-02  8:42     ` Andrey Albershteyn
2024-04-02 16:34       ` Darrick J. Wong
2024-04-25  1:14         ` Darrick J. Wong
2024-03-30  0:39   ` [PATCH 14/29] xfs: create a per-mount shrinker for verity inodes merkle tree blocks Darrick J. Wong
2024-04-05  3:16     ` Eric Biggers
2024-04-24 17:39       ` Darrick J. Wong
2024-03-30  0:39   ` [PATCH 15/29] xfs: create an icache tag for files with cached " Darrick J. Wong
2024-03-30  0:40   ` [PATCH 16/29] xfs: shrink verity blob cache Darrick J. Wong
2024-03-30  0:40   ` [PATCH 17/29] xfs: only allow the verity iflag for regular files Darrick J. Wong
2024-04-02 12:52     ` Andrey Albershteyn
2024-03-30  0:40   ` [PATCH 18/29] xfs: don't store trailing zeroes of merkle tree blocks Darrick J. Wong
2024-03-30  0:41   ` [PATCH 19/29] xfs: use merkle tree offset as attr hash Darrick J. Wong
2024-03-30  0:41   ` [PATCH 20/29] xfs: don't bother storing merkle tree blocks for zeroed data blocks Darrick J. Wong
2024-03-30  0:41   ` [PATCH 21/29] xfs: add fs-verity ioctls Darrick J. Wong
2024-03-30  0:41   ` [PATCH 22/29] xfs: advertise fs-verity being available on filesystem Darrick J. Wong
2024-04-02 13:44     ` Andrey Albershteyn
2024-03-30  0:42   ` [PATCH 23/29] xfs: make scrub aware of verity dinode flag Darrick J. Wong
2024-03-30  0:42   ` [PATCH 24/29] xfs: teach online repair to evaluate fsverity xattrs Darrick J. Wong
2024-04-02 15:42     ` Andrey Albershteyn
2024-04-02 16:42       ` Darrick J. Wong
2024-03-30  0:42   ` [PATCH 25/29] xfs: report verity failures through the health system Darrick J. Wong
2024-04-02 16:16     ` Andrey Albershteyn
2024-03-30  0:42   ` [PATCH 26/29] xfs: clear the verity iflag when not appropriate Darrick J. Wong
2024-04-02 16:26     ` Andrey Albershteyn
2024-03-30  0:43   ` [PATCH 27/29] xfs: make it possible to disable fsverity Darrick J. Wong
2024-04-02 17:15     ` Andrey Albershteyn
2024-04-02 23:25     ` Eric Biggers
2024-04-03  1:26       ` Darrick J. Wong
2024-03-30  0:43   ` [PATCH 28/29] xfs: allow verity files to be opened even if the fsverity metadata is damaged Darrick J. Wong
2024-04-02 18:04     ` Andrey Albershteyn
2024-04-02 20:00     ` Colin Walters
2024-04-02 22:52       ` Darrick J. Wong
2024-04-02 23:45         ` Eric Biggers
2024-04-03  1:34           ` Darrick J. Wong
2024-04-03  0:10         ` Colin Walters
2024-04-03  1:39           ` Darrick J. Wong
2024-04-03  1:59             ` Dave Chinner
2024-04-03  3:19               ` Darrick J. Wong
2024-04-03 22:22                 ` Dave Chinner
2024-04-03  8:35           ` Alexander Larsson
2024-03-30  0:43   ` [PATCH 29/29] xfs: enable ro-compat fs-verity flag Darrick J. Wong

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=20240405023145.GB1958@quark.localdomain \
    --to=ebiggers@kernel.org \
    --cc=aalbersh@redhat.com \
    --cc=djwong@kernel.org \
    --cc=fsverity@lists.linux.dev \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-xfs@vger.kernel.org \
    /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 read-only IMAP folder(s) and NNTP newsgroup(s).