Skip to contentSkip to conversation

fs-verity: use mempool for hash requests

PATCH Applied Eric Biggers 2 participants 3 messages Dec 31, 2019 – Jan 14, 2020

Subsystems (2)
lore
Share & tools
lore

Eric Biggers

author maintainer
#0 lore raw

PATCH 1/1 fs-verity: use mempool for hash requests

From: Eric Biggers <[email protected]>

When initializing an fs-verity hash algorithm, also initialize a mempool that contains a single preallocated hash request object. Then replace the direct calls to ahash_request_alloc() and ahash_request_free() with allocating and freeing from this mempool.

This eliminates the possibility of the allocation failing, which is desirable for the I/O path.

This doesn't cause deadlocks because there's no case where multiple hash requests are needed at a time to make forward progress.

---
 fs/verity/enable.c           |  8 +--
 fs/verity/fsverity_private.h | 16 ++++--
 fs/verity/hash_algs.c        | 98 +++++++++++++++++++++++++++---------
 fs/verity/open.c             |  4 +-
 fs/verity/verify.c           | 17 +++----
 5 files changed, 97 insertions(+), 46 deletions(-)
fs/verity/enable.c +5 -3
index 1f3858d88cf3..1645d6326e32 100644
@@ -165,9 +165,11 @@ static int build_merkle_tree(struct file *filp,
 		return 0;
 	}
 
+	/* This allocation never fails, since it's mempool-backed. */
+	req = fsverity_alloc_hash_request(params->hash_alg, GFP_KERNEL);
+
 	pending_hashes = kmalloc(params->block_size, GFP_KERNEL);
-	req = ahash_request_alloc(params->hash_alg->tfm, GFP_KERNEL);
-	if (!pending_hashes || !req)
+	if (!pending_hashes)
 		goto out;
 
 	/*
@@ -189,7 +191,7 @@ static int build_merkle_tree(struct file *filp,
 	err = 0;
 out:
 	kfree(pending_hashes);
-	ahash_request_free(req);
+	fsverity_free_hash_request(params->hash_alg, req);
 	return err;
 }
 
fs/verity/fsverity_private.h +11 -5
index ab9cfdd8f965..74768cf539da 100644
@@ -16,6 +16,7 @@
 
 #include <crypto/sha.h>
 #include <linux/fsverity.h>
+#include <linux/mempool.h>
 
 struct ahash_request;
 
@@ -37,11 +38,12 @@ struct fsverity_hash_alg {
 	const char *name;	  /* crypto API name, e.g. sha256 */
 	unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
 	unsigned int block_size;  /* block size in bytes, e.g. 64 for SHA-256 */
+	mempool_t req_pool;	  /* mempool with a preallocated hash request */
 };
 
 /* Merkle tree parameters: hash algorithm, initial hash state, and topology */
 struct merkle_tree_params {
-	const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
+	struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
 	const u8 *hashstate;		/* initial hash state or NULL */
 	unsigned int digest_size;	/* same as hash_alg->digest_size */
 	unsigned int block_size;	/* size of data and tree blocks */
@@ -115,14 +117,18 @@ struct fsverity_signed_digest {
 
 extern struct fsverity_hash_alg fsverity_hash_algs[];
 
-const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
-						      unsigned int num);
-const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
+struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
+						unsigned int num);
+struct ahash_request *fsverity_alloc_hash_request(struct fsverity_hash_alg *alg,
+						  gfp_t gfp_flags);
+void fsverity_free_hash_request(struct fsverity_hash_alg *alg,
+				struct ahash_request *req);
+const u8 *fsverity_prepare_hash_state(struct fsverity_hash_alg *alg,
 				      const u8 *salt, size_t salt_size);
 int fsverity_hash_page(const struct merkle_tree_params *params,
 		       const struct inode *inode,
 		       struct ahash_request *req, struct page *page, u8 *out);
-int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
+int fsverity_hash_buffer(struct fsverity_hash_alg *alg,
 			 const void *data, size_t size, u8 *out);
 void __init fsverity_check_hash_algs(void);
 
fs/verity/hash_algs.c +73 -25

175 lines not on this page · raw message

fs/verity/open.c +2 -2
index e9cdf7d00ed2..c5fe6948e262 100644
@@ -31,7 +31,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
 				     unsigned int log_blocksize,
 				     const u8 *salt, size_t salt_size)
 {
-	const struct fsverity_hash_alg *hash_alg;
+	struct fsverity_hash_alg *hash_alg;
 	int err;
 	u64 blocks;
 	u64 offset;
@@ -127,7 +127,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
  * Compute the file measurement by hashing the fsverity_descriptor excluding the
  * signature and with the sig_size field set to 0.
  */
-static int compute_file_measurement(const struct fsverity_hash_alg *hash_alg,
+static int compute_file_measurement(struct fsverity_hash_alg *hash_alg,
 				    struct fsverity_descriptor *desc,
 				    u8 *measurement)
 {
fs/verity/verify.c +6 -11
index 7fa561c343c2..e0cb62da3864 100644
@@ -192,13 +192,12 @@ bool fsverity_verify_page(struct page *page)
 	struct ahash_request *req;
 	bool valid;
 
-	req = ahash_request_alloc(vi->tree_params.hash_alg->tfm, GFP_NOFS);
-	if (unlikely(!req))
-		return false;
+	/* This allocation never fails, since it's mempool-backed. */
+	req = fsverity_alloc_hash_request(vi->tree_params.hash_alg, GFP_NOFS);
 
 	valid = verify_page(inode, vi, req, page, 0);
 
-	ahash_request_free(req);
+	fsverity_free_hash_request(vi->tree_params.hash_alg, req);
 
 	return valid;
 }
@@ -229,12 +228,8 @@ void fsverity_verify_bio(struct bio *bio)
 	struct bvec_iter_all iter_all;
 	unsigned long max_ra_pages = 0;
 
-	req = ahash_request_alloc(params->hash_alg->tfm, GFP_NOFS);
-	if (unlikely(!req)) {
-		bio_for_each_segment_all(bv, bio, iter_all)
-			SetPageError(bv->bv_page);
-		return;
-	}
+	/* This allocation never fails, since it's mempool-backed. */
+	req = fsverity_alloc_hash_request(params->hash_alg, GFP_NOFS);
 
 	if (bio->bi_opf & REQ_RAHEAD) {
 		/*
@@ -262,7 +257,7 @@ void fsverity_verify_bio(struct bio *bio)
 			SetPageError(page);
 	}
 
-	ahash_request_free(req);
+	fsverity_free_hash_request(params->hash_alg, req);
 }
 EXPORT_SYMBOL_GPL(fsverity_verify_bio);
 #endif /* CONFIG_BLOCK */
Signature · 1 line
2.24.1
maintainer Reviewed-by on v1 1/1
#1 lore raw
Quoted 7 lines · Eric Biggers

From: Eric Biggers <[email protected]>

When initializing an fs-verity hash algorithm, also initialize a mempool that contains a single preallocated hash request object. Then replace the direct calls to ahash_request_alloc() and ahash_request_free() with allocating and freeing from this mempool.

Quoted 7 lines

This eliminates the possibility of the allocation failing, which is desirable for the I/O path.

This doesn't cause deadlocks because there's no case where multiple hash requests are needed at a time to make forward progress.

Looks good; feel free to add:

author maintainer Applied
#2 lore raw
In reply to Eric Biggers
Quoted 13 lines · Eric Biggers

From: Eric Biggers <[email protected]>

When initializing an fs-verity hash algorithm, also initialize a mempool that contains a single preallocated hash request object. Then replace the direct calls to ahash_request_alloc() and ahash_request_free() with allocating and freeing from this mempool.

This eliminates the possibility of the allocation failing, which is desirable for the I/O path.

This doesn't cause deadlocks because there's no case where multiple hash requests are needed at a time to make forward progress.

Quoted 9 lines
---
 fs/verity/enable.c           |  8 +--
 fs/verity/fsverity_private.h | 16 ++++--
 fs/verity/hash_algs.c        | 98 +++++++++++++++++++++++++++---------
 fs/verity/open.c             |  4 +-
 fs/verity/verify.c           | 17 +++----
 5 files changed, 97 insertions(+), 46 deletions(-)

Applied to fscrypt.git#fsverity for 5.6.

- Eric