162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Data verification functions, i.e. hooks for ->readahead()
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2019 Google LLC
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "fsverity_private.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <crypto/hash.h>
1162306a36Sopenharmony_ci#include <linux/bio.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic struct workqueue_struct *fsverity_read_workqueue;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Returns true if the hash block with index @hblock_idx in the tree, located in
1762306a36Sopenharmony_ci * @hpage, has already been verified.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_cistatic bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,
2062306a36Sopenharmony_ci				   unsigned long hblock_idx)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	bool verified;
2362306a36Sopenharmony_ci	unsigned int blocks_per_page;
2462306a36Sopenharmony_ci	unsigned int i;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	/*
2762306a36Sopenharmony_ci	 * When the Merkle tree block size and page size are the same, then the
2862306a36Sopenharmony_ci	 * ->hash_block_verified bitmap isn't allocated, and we use PG_checked
2962306a36Sopenharmony_ci	 * to directly indicate whether the page's block has been verified.
3062306a36Sopenharmony_ci	 *
3162306a36Sopenharmony_ci	 * Using PG_checked also guarantees that we re-verify hash pages that
3262306a36Sopenharmony_ci	 * get evicted and re-instantiated from the backing storage, as new
3362306a36Sopenharmony_ci	 * pages always start out with PG_checked cleared.
3462306a36Sopenharmony_ci	 */
3562306a36Sopenharmony_ci	if (!vi->hash_block_verified)
3662306a36Sopenharmony_ci		return PageChecked(hpage);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/*
3962306a36Sopenharmony_ci	 * When the Merkle tree block size and page size differ, we use a bitmap
4062306a36Sopenharmony_ci	 * to indicate whether each hash block has been verified.
4162306a36Sopenharmony_ci	 *
4262306a36Sopenharmony_ci	 * However, we still need to ensure that hash pages that get evicted and
4362306a36Sopenharmony_ci	 * re-instantiated from the backing storage are re-verified.  To do
4462306a36Sopenharmony_ci	 * this, we use PG_checked again, but now it doesn't really mean
4562306a36Sopenharmony_ci	 * "checked".  Instead, now it just serves as an indicator for whether
4662306a36Sopenharmony_ci	 * the hash page is newly instantiated or not.
4762306a36Sopenharmony_ci	 *
4862306a36Sopenharmony_ci	 * The first thread that sees PG_checked=0 must clear the corresponding
4962306a36Sopenharmony_ci	 * bitmap bits, then set PG_checked=1.  This requires a spinlock.  To
5062306a36Sopenharmony_ci	 * avoid having to take this spinlock in the common case of
5162306a36Sopenharmony_ci	 * PG_checked=1, we start with an opportunistic lockless read.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	if (PageChecked(hpage)) {
5462306a36Sopenharmony_ci		/*
5562306a36Sopenharmony_ci		 * A read memory barrier is needed here to give ACQUIRE
5662306a36Sopenharmony_ci		 * semantics to the above PageChecked() test.
5762306a36Sopenharmony_ci		 */
5862306a36Sopenharmony_ci		smp_rmb();
5962306a36Sopenharmony_ci		return test_bit(hblock_idx, vi->hash_block_verified);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	spin_lock(&vi->hash_page_init_lock);
6262306a36Sopenharmony_ci	if (PageChecked(hpage)) {
6362306a36Sopenharmony_ci		verified = test_bit(hblock_idx, vi->hash_block_verified);
6462306a36Sopenharmony_ci	} else {
6562306a36Sopenharmony_ci		blocks_per_page = vi->tree_params.blocks_per_page;
6662306a36Sopenharmony_ci		hblock_idx = round_down(hblock_idx, blocks_per_page);
6762306a36Sopenharmony_ci		for (i = 0; i < blocks_per_page; i++)
6862306a36Sopenharmony_ci			clear_bit(hblock_idx + i, vi->hash_block_verified);
6962306a36Sopenharmony_ci		/*
7062306a36Sopenharmony_ci		 * A write memory barrier is needed here to give RELEASE
7162306a36Sopenharmony_ci		 * semantics to the below SetPageChecked() operation.
7262306a36Sopenharmony_ci		 */
7362306a36Sopenharmony_ci		smp_wmb();
7462306a36Sopenharmony_ci		SetPageChecked(hpage);
7562306a36Sopenharmony_ci		verified = false;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	spin_unlock(&vi->hash_page_init_lock);
7862306a36Sopenharmony_ci	return verified;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/*
8262306a36Sopenharmony_ci * Verify a single data block against the file's Merkle tree.
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * In principle, we need to verify the entire path to the root node.  However,
8562306a36Sopenharmony_ci * for efficiency the filesystem may cache the hash blocks.  Therefore we need
8662306a36Sopenharmony_ci * only ascend the tree until an already-verified hash block is seen, and then
8762306a36Sopenharmony_ci * verify the path to that block.
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * Return: %true if the data block is valid, else %false.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistatic bool
9262306a36Sopenharmony_civerify_data_block(struct inode *inode, struct fsverity_info *vi,
9362306a36Sopenharmony_ci		  const void *data, u64 data_pos, unsigned long max_ra_pages)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	const struct merkle_tree_params *params = &vi->tree_params;
9662306a36Sopenharmony_ci	const unsigned int hsize = params->digest_size;
9762306a36Sopenharmony_ci	int level;
9862306a36Sopenharmony_ci	u8 _want_hash[FS_VERITY_MAX_DIGEST_SIZE];
9962306a36Sopenharmony_ci	const u8 *want_hash;
10062306a36Sopenharmony_ci	u8 real_hash[FS_VERITY_MAX_DIGEST_SIZE];
10162306a36Sopenharmony_ci	/* The hash blocks that are traversed, indexed by level */
10262306a36Sopenharmony_ci	struct {
10362306a36Sopenharmony_ci		/* Page containing the hash block */
10462306a36Sopenharmony_ci		struct page *page;
10562306a36Sopenharmony_ci		/* Mapped address of the hash block (will be within @page) */
10662306a36Sopenharmony_ci		const void *addr;
10762306a36Sopenharmony_ci		/* Index of the hash block in the tree overall */
10862306a36Sopenharmony_ci		unsigned long index;
10962306a36Sopenharmony_ci		/* Byte offset of the wanted hash relative to @addr */
11062306a36Sopenharmony_ci		unsigned int hoffset;
11162306a36Sopenharmony_ci	} hblocks[FS_VERITY_MAX_LEVELS];
11262306a36Sopenharmony_ci	/*
11362306a36Sopenharmony_ci	 * The index of the previous level's block within that level; also the
11462306a36Sopenharmony_ci	 * index of that block's hash within the current level.
11562306a36Sopenharmony_ci	 */
11662306a36Sopenharmony_ci	u64 hidx = data_pos >> params->log_blocksize;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* Up to 1 + FS_VERITY_MAX_LEVELS pages may be mapped at once */
11962306a36Sopenharmony_ci	BUILD_BUG_ON(1 + FS_VERITY_MAX_LEVELS > KM_MAX_IDX);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (unlikely(data_pos >= inode->i_size)) {
12262306a36Sopenharmony_ci		/*
12362306a36Sopenharmony_ci		 * This can happen in the data page spanning EOF when the Merkle
12462306a36Sopenharmony_ci		 * tree block size is less than the page size.  The Merkle tree
12562306a36Sopenharmony_ci		 * doesn't cover data blocks fully past EOF.  But the entire
12662306a36Sopenharmony_ci		 * page spanning EOF can be visible to userspace via a mmap, and
12762306a36Sopenharmony_ci		 * any part past EOF should be all zeroes.  Therefore, we need
12862306a36Sopenharmony_ci		 * to verify that any data blocks fully past EOF are all zeroes.
12962306a36Sopenharmony_ci		 */
13062306a36Sopenharmony_ci		if (memchr_inv(data, 0, params->block_size)) {
13162306a36Sopenharmony_ci			fsverity_err(inode,
13262306a36Sopenharmony_ci				     "FILE CORRUPTED!  Data past EOF is not zeroed");
13362306a36Sopenharmony_ci			return false;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci		return true;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_CODE_SIGN
13962306a36Sopenharmony_ci	if (data_pos >= vi->verified_data_size) {
14062306a36Sopenharmony_ci		pr_debug_ratelimited("Data[%lu] out of verity range %lu\n",
14162306a36Sopenharmony_ci			data_pos, vi->verified_data_size);
14262306a36Sopenharmony_ci		return true;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci#endif
14562306a36Sopenharmony_ci	/*
14662306a36Sopenharmony_ci	 * Starting at the leaf level, ascend the tree saving hash blocks along
14762306a36Sopenharmony_ci	 * the way until we find a hash block that has already been verified, or
14862306a36Sopenharmony_ci	 * until we reach the root.
14962306a36Sopenharmony_ci	 */
15062306a36Sopenharmony_ci	for (level = 0; level < params->num_levels; level++) {
15162306a36Sopenharmony_ci		unsigned long next_hidx;
15262306a36Sopenharmony_ci		unsigned long hblock_idx;
15362306a36Sopenharmony_ci		pgoff_t hpage_idx;
15462306a36Sopenharmony_ci		unsigned int hblock_offset_in_page;
15562306a36Sopenharmony_ci		unsigned int hoffset;
15662306a36Sopenharmony_ci		struct page *hpage;
15762306a36Sopenharmony_ci		const void *haddr;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		/*
16062306a36Sopenharmony_ci		 * The index of the block in the current level; also the index
16162306a36Sopenharmony_ci		 * of that block's hash within the next level.
16262306a36Sopenharmony_ci		 */
16362306a36Sopenharmony_ci		next_hidx = hidx >> params->log_arity;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		/* Index of the hash block in the tree overall */
16662306a36Sopenharmony_ci		hblock_idx = params->level_start[level] + next_hidx;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		/* Index of the hash page in the tree overall */
16962306a36Sopenharmony_ci		hpage_idx = hblock_idx >> params->log_blocks_per_page;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		/* Byte offset of the hash block within the page */
17262306a36Sopenharmony_ci		hblock_offset_in_page =
17362306a36Sopenharmony_ci			(hblock_idx << params->log_blocksize) & ~PAGE_MASK;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		/* Byte offset of the hash within the block */
17662306a36Sopenharmony_ci		hoffset = (hidx << params->log_digestsize) &
17762306a36Sopenharmony_ci			  (params->block_size - 1);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode,
18062306a36Sopenharmony_ci				hpage_idx, level == 0 ? min(max_ra_pages,
18162306a36Sopenharmony_ci					params->tree_pages - hpage_idx) : 0);
18262306a36Sopenharmony_ci		if (IS_ERR(hpage)) {
18362306a36Sopenharmony_ci			fsverity_err(inode,
18462306a36Sopenharmony_ci				     "Error %ld reading Merkle tree page %lu",
18562306a36Sopenharmony_ci				     PTR_ERR(hpage), hpage_idx);
18662306a36Sopenharmony_ci			goto error;
18762306a36Sopenharmony_ci		}
18862306a36Sopenharmony_ci		haddr = kmap_local_page(hpage) + hblock_offset_in_page;
18962306a36Sopenharmony_ci		if (is_hash_block_verified(vi, hpage, hblock_idx)) {
19062306a36Sopenharmony_ci			memcpy(_want_hash, haddr + hoffset, hsize);
19162306a36Sopenharmony_ci			want_hash = _want_hash;
19262306a36Sopenharmony_ci			kunmap_local(haddr);
19362306a36Sopenharmony_ci			put_page(hpage);
19462306a36Sopenharmony_ci			goto descend;
19562306a36Sopenharmony_ci		}
19662306a36Sopenharmony_ci		hblocks[level].page = hpage;
19762306a36Sopenharmony_ci		hblocks[level].addr = haddr;
19862306a36Sopenharmony_ci		hblocks[level].index = hblock_idx;
19962306a36Sopenharmony_ci		hblocks[level].hoffset = hoffset;
20062306a36Sopenharmony_ci		hidx = next_hidx;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	want_hash = vi->root_hash;
20462306a36Sopenharmony_cidescend:
20562306a36Sopenharmony_ci	/* Descend the tree verifying hash blocks. */
20662306a36Sopenharmony_ci	for (; level > 0; level--) {
20762306a36Sopenharmony_ci		struct page *hpage = hblocks[level - 1].page;
20862306a36Sopenharmony_ci		const void *haddr = hblocks[level - 1].addr;
20962306a36Sopenharmony_ci		unsigned long hblock_idx = hblocks[level - 1].index;
21062306a36Sopenharmony_ci		unsigned int hoffset = hblocks[level - 1].hoffset;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		if (fsverity_hash_block(params, inode, haddr, real_hash) != 0)
21362306a36Sopenharmony_ci			goto error;
21462306a36Sopenharmony_ci		if (memcmp(want_hash, real_hash, hsize) != 0)
21562306a36Sopenharmony_ci			goto corrupted;
21662306a36Sopenharmony_ci		/*
21762306a36Sopenharmony_ci		 * Mark the hash block as verified.  This must be atomic and
21862306a36Sopenharmony_ci		 * idempotent, as the same hash block might be verified by
21962306a36Sopenharmony_ci		 * multiple threads concurrently.
22062306a36Sopenharmony_ci		 */
22162306a36Sopenharmony_ci		if (vi->hash_block_verified)
22262306a36Sopenharmony_ci			set_bit(hblock_idx, vi->hash_block_verified);
22362306a36Sopenharmony_ci		else
22462306a36Sopenharmony_ci			SetPageChecked(hpage);
22562306a36Sopenharmony_ci		memcpy(_want_hash, haddr + hoffset, hsize);
22662306a36Sopenharmony_ci		want_hash = _want_hash;
22762306a36Sopenharmony_ci		kunmap_local(haddr);
22862306a36Sopenharmony_ci		put_page(hpage);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Finally, verify the data block. */
23262306a36Sopenharmony_ci	if (fsverity_hash_block(params, inode, data, real_hash) != 0)
23362306a36Sopenharmony_ci		goto error;
23462306a36Sopenharmony_ci	if (memcmp(want_hash, real_hash, hsize) != 0)
23562306a36Sopenharmony_ci		goto corrupted;
23662306a36Sopenharmony_ci	return true;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cicorrupted:
23962306a36Sopenharmony_ci	fsverity_err(inode,
24062306a36Sopenharmony_ci		     "FILE CORRUPTED! pos=%llu, level=%d, want_hash=%s:%*phN, real_hash=%s:%*phN",
24162306a36Sopenharmony_ci		     data_pos, level - 1,
24262306a36Sopenharmony_ci		     params->hash_alg->name, hsize, want_hash,
24362306a36Sopenharmony_ci		     params->hash_alg->name, hsize, real_hash);
24462306a36Sopenharmony_cierror:
24562306a36Sopenharmony_ci	for (; level > 0; level--) {
24662306a36Sopenharmony_ci		kunmap_local(hblocks[level - 1].addr);
24762306a36Sopenharmony_ci		put_page(hblocks[level - 1].page);
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	return false;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic bool
25362306a36Sopenharmony_civerify_data_blocks(struct folio *data_folio, size_t len, size_t offset,
25462306a36Sopenharmony_ci		   unsigned long max_ra_pages)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct inode *inode = data_folio->mapping->host;
25762306a36Sopenharmony_ci	struct fsverity_info *vi = inode->i_verity_info;
25862306a36Sopenharmony_ci	const unsigned int block_size = vi->tree_params.block_size;
25962306a36Sopenharmony_ci	u64 pos = (u64)data_folio->index << PAGE_SHIFT;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offset, block_size)))
26262306a36Sopenharmony_ci		return false;
26362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!folio_test_locked(data_folio) ||
26462306a36Sopenharmony_ci			 folio_test_uptodate(data_folio)))
26562306a36Sopenharmony_ci		return false;
26662306a36Sopenharmony_ci	do {
26762306a36Sopenharmony_ci		void *data;
26862306a36Sopenharmony_ci		bool valid;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		data = kmap_local_folio(data_folio, offset);
27162306a36Sopenharmony_ci		valid = verify_data_block(inode, vi, data, pos + offset,
27262306a36Sopenharmony_ci					  max_ra_pages);
27362306a36Sopenharmony_ci		kunmap_local(data);
27462306a36Sopenharmony_ci		if (!valid)
27562306a36Sopenharmony_ci			return false;
27662306a36Sopenharmony_ci		offset += block_size;
27762306a36Sopenharmony_ci		len -= block_size;
27862306a36Sopenharmony_ci	} while (len);
27962306a36Sopenharmony_ci	return true;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/**
28362306a36Sopenharmony_ci * fsverity_verify_blocks() - verify data in a folio
28462306a36Sopenharmony_ci * @folio: the folio containing the data to verify
28562306a36Sopenharmony_ci * @len: the length of the data to verify in the folio
28662306a36Sopenharmony_ci * @offset: the offset of the data to verify in the folio
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * Verify data that has just been read from a verity file.  The data must be
28962306a36Sopenharmony_ci * located in a pagecache folio that is still locked and not yet uptodate.  The
29062306a36Sopenharmony_ci * length and offset of the data must be Merkle tree block size aligned.
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * Return: %true if the data is valid, else %false.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_cibool fsverity_verify_blocks(struct folio *folio, size_t len, size_t offset)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	return verify_data_blocks(folio, len, offset, 0);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_verify_blocks);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci#ifdef CONFIG_BLOCK
30162306a36Sopenharmony_ci/**
30262306a36Sopenharmony_ci * fsverity_verify_bio() - verify a 'read' bio that has just completed
30362306a36Sopenharmony_ci * @bio: the bio to verify
30462306a36Sopenharmony_ci *
30562306a36Sopenharmony_ci * Verify the bio's data against the file's Merkle tree.  All bio data segments
30662306a36Sopenharmony_ci * must be aligned to the file's Merkle tree block size.  If any data fails
30762306a36Sopenharmony_ci * verification, then bio->bi_status is set to an error status.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * This is a helper function for use by the ->readahead() method of filesystems
31062306a36Sopenharmony_ci * that issue bios to read data directly into the page cache.  Filesystems that
31162306a36Sopenharmony_ci * populate the page cache without issuing bios (e.g. non block-based
31262306a36Sopenharmony_ci * filesystems) must instead call fsverity_verify_page() directly on each page.
31362306a36Sopenharmony_ci * All filesystems must also call fsverity_verify_page() on holes.
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_civoid fsverity_verify_bio(struct bio *bio)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct folio_iter fi;
31862306a36Sopenharmony_ci	unsigned long max_ra_pages = 0;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (bio->bi_opf & REQ_RAHEAD) {
32162306a36Sopenharmony_ci		/*
32262306a36Sopenharmony_ci		 * If this bio is for data readahead, then we also do readahead
32362306a36Sopenharmony_ci		 * of the first (largest) level of the Merkle tree.  Namely,
32462306a36Sopenharmony_ci		 * when a Merkle tree page is read, we also try to piggy-back on
32562306a36Sopenharmony_ci		 * some additional pages -- up to 1/4 the number of data pages.
32662306a36Sopenharmony_ci		 *
32762306a36Sopenharmony_ci		 * This improves sequential read performance, as it greatly
32862306a36Sopenharmony_ci		 * reduces the number of I/O requests made to the Merkle tree.
32962306a36Sopenharmony_ci		 */
33062306a36Sopenharmony_ci		max_ra_pages = bio->bi_iter.bi_size >> (PAGE_SHIFT + 2);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	bio_for_each_folio_all(fi, bio) {
33462306a36Sopenharmony_ci		if (!verify_data_blocks(fi.folio, fi.length, fi.offset,
33562306a36Sopenharmony_ci					max_ra_pages)) {
33662306a36Sopenharmony_ci			bio->bi_status = BLK_STS_IOERR;
33762306a36Sopenharmony_ci			break;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_verify_bio);
34262306a36Sopenharmony_ci#endif /* CONFIG_BLOCK */
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci/**
34562306a36Sopenharmony_ci * fsverity_get_verified_data_size() - get verified data size of a verity file
34662306a36Sopenharmony_ci * @inode: the file's inode
34762306a36Sopenharmony_ci *
34862306a36Sopenharmony_ci * Return: verified data size
34962306a36Sopenharmony_ci */
35062306a36Sopenharmony_ciu64 fsverity_get_verified_data_size(const struct inode *inode)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_CODE_SIGN
35362306a36Sopenharmony_ci	return fsverity_get_info(inode)->verified_data_size;
35462306a36Sopenharmony_ci#else
35562306a36Sopenharmony_ci	return inode->i_size;
35662306a36Sopenharmony_ci#endif
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/**
36062306a36Sopenharmony_ci * fsverity_enqueue_verify_work() - enqueue work on the fs-verity workqueue
36162306a36Sopenharmony_ci * @work: the work to enqueue
36262306a36Sopenharmony_ci *
36362306a36Sopenharmony_ci * Enqueue verification work for asynchronous processing.
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_civoid fsverity_enqueue_verify_work(struct work_struct *work)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	queue_work(fsverity_read_workqueue, work);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_enqueue_verify_work);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_civoid __init fsverity_init_workqueue(void)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	/*
37462306a36Sopenharmony_ci	 * Use a high-priority workqueue to prioritize verification work, which
37562306a36Sopenharmony_ci	 * blocks reads from completing, over regular application tasks.
37662306a36Sopenharmony_ci	 *
37762306a36Sopenharmony_ci	 * For performance reasons, don't use an unbound workqueue.  Using an
37862306a36Sopenharmony_ci	 * unbound workqueue for crypto operations causes excessive scheduler
37962306a36Sopenharmony_ci	 * latency on ARM64.
38062306a36Sopenharmony_ci	 */
38162306a36Sopenharmony_ci	fsverity_read_workqueue = alloc_workqueue("fsverity_read_queue",
38262306a36Sopenharmony_ci						  WQ_HIGHPRI,
38362306a36Sopenharmony_ci						  num_online_cpus());
38462306a36Sopenharmony_ci	if (!fsverity_read_workqueue)
38562306a36Sopenharmony_ci		panic("failed to allocate fsverity_read_queue");
38662306a36Sopenharmony_ci}
387