Skip to contentSkip to conversation

Convert fs/verity/ to use SHA-2 library API

PATCH In review Eric Biggers 2 participants 6 messages Jun 30, 2025 – Jul 9, 2025

Subsystems (5)
lore
Share & tools
lore

Eric Biggers

author maintainer
#0 lore raw

cover Convert fs/verity/ to use SHA-2 library API

This series, including all its prerequisites, is also available at:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git fsverity-libcrypto-v1

This series makes fs/verity/ use the SHA-2 library API instead of the old-school crypto API. This is simpler and more efficient.

This depends on my SHA-2 library improvements for 6.17 (many patches), so this patchset might need to wait until 6.18. But I'm also thinking about just basing the fsverity tree on libcrypto-next for 6.17.

Eric Biggers (2):
lib/crypto: hash_info: Move hash_info.c into lib/crypto/
fsverity: Switch from crypto_shash to SHA-2 library

 Documentation/filesystems/fsverity.rst |   3 +-
 crypto/Kconfig                         |   3 -
 crypto/Makefile                        |   1 -
 fs/verity/Kconfig                      |   6 +-
 fs/verity/enable.c                     |   8 +-
 fs/verity/fsverity_private.h           |  24 +--
 fs/verity/hash_algs.c                  | 194 +++++++++----------------
 fs/verity/open.c                       |  36 ++---
 fs/verity/verify.c                     |   7 +-
 lib/crypto/Kconfig                     |   3 +
 lib/crypto/Makefile                    |   2 +
 {crypto => lib/crypto}/hash_info.c     |   0
 12 files changed, 107 insertions(+), 180 deletions(-)
 rename {crypto => lib/crypto}/hash_info.c (100%)
Signature · 1 line
2.50.0
author maintainer
#1 lore raw

PATCH 1/2 lib/crypto: hash_info: Move hash_info.c into lib/crypto/

crypto/hash_info.c just contains a couple of arrays that map HASH_ALGO_* algorithm IDs to properties of those algorithms. It is compiled only when CRYPTO_HASH_INFO=y, but currently CRYPTO_HASH_INFO depends on CRYPTO. Since this can be useful without the old-school crypto API, move it into lib/crypto/ so that it no longer depends on CRYPTO.

This eliminates the need for FS_VERITY to select CRYPTO after it's been converted to use lib/crypto/.

---
 crypto/Kconfig                     | 3 ---
 crypto/Makefile                    | 1 -
 lib/crypto/Kconfig                 | 3 +++
 lib/crypto/Makefile                | 2 ++
 {crypto => lib/crypto}/hash_info.c | 0
 5 files changed, 5 insertions(+), 4 deletions(-)
 rename {crypto => lib/crypto}/hash_info.c (100%)
crypto/Kconfig +0 -3
index 3ea1397214e02..5d4cf022c5775 100644
@@ -1420,13 +1420,10 @@ config CRYPTO_USER_API_ENABLE_OBSOLETE
 	  already been phased out from internal use by the kernel, and are
 	  only useful for userspace clients that still rely on them.
 
 endmenu
 
-config CRYPTO_HASH_INFO
-	bool
-
 if !KMSAN # avoid false positives from assembly
 if ARM
 source "arch/arm/crypto/Kconfig"
 endif
 if ARM64
crypto/Makefile +0 -1
index 5098fa6d5f39c..816607e0e78ce 100644
@@ -202,11 +202,10 @@ obj-$(CONFIG_CRYPTO_ECRDSA) += ecrdsa_generic.o
 # generic algorithms and the async_tx api
 #
 obj-$(CONFIG_XOR_BLOCKS) += xor.o
 obj-$(CONFIG_ASYNC_CORE) += async_tx/
 obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
-obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o
 crypto_simd-y := simd.o
 obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
 
 #
 # Key derivation function
lib/crypto/Kconfig +3 -0
index 3305c69085816..cce53ae15cd58 100644
@@ -3,10 +3,13 @@
 menu "Crypto library routines"
 
 config CRYPTO_LIB_UTILS
 	tristate
 
+config CRYPTO_HASH_INFO
+	bool
+
 config CRYPTO_LIB_AES
 	tristate
 
 config CRYPTO_LIB_AESCFB
 	tristate
lib/crypto/Makefile +2 -0
index a887bf103bf05..533bb1533e19b 100644
@@ -6,10 +6,12 @@ quiet_cmd_perlasm = PERLASM $@
       cmd_perlasm = $(PERL) $(<) > $(@)
 
 quiet_cmd_perlasm_with_args = PERLASM $@
       cmd_perlasm_with_args = $(PERL) $(<) void $(@)
 
+obj-$(CONFIG_CRYPTO_HASH_INFO)			+= hash_info.o
+
 obj-$(CONFIG_CRYPTO_LIB_UTILS)			+= libcryptoutils.o
 libcryptoutils-y				:= memneq.o utils.o
 
 # chacha is used by the /dev/random driver which is always builtin
 obj-y						+= chacha.o
lib/crypto/hash_info.c renamed from crypto/hash_info.c +0 -0
similarity index 100%
rename from crypto/hash_info.c
rename to lib/crypto/hash_info.c
Signature · 1 line
2.50.0
author maintainer
#2 lore raw

PATCH 2/2 fsverity: Switch from crypto_shash to SHA-2 library

In reply to Eric Biggers

fsverity supports two hash algorithms: SHA-256 and SHA-512. Since both of these have a library API now, just use the library API instead of crypto_shash. Even with multiple algorithms, the library-based code still ends up being quite a bit simpler, due to how clumsy the old-school crypto API is. The library-based code is also more efficient, since it avoids overheads such as indirect calls.

---
 Documentation/filesystems/fsverity.rst |   3 +-
 fs/verity/Kconfig                      |   6 +-
 fs/verity/enable.c                     |   8 +-
 fs/verity/fsverity_private.h           |  24 +--
 fs/verity/hash_algs.c                  | 194 +++++++++----------------
 fs/verity/open.c                       |  36 ++---
 fs/verity/verify.c                     |   7 +-
 7 files changed, 102 insertions(+), 176 deletions(-)
Documentation/filesystems/fsverity.rst +1 -2
index dacdbc1149e67..412cf11e32985 100644
@@ -183,12 +183,11 @@ FS_IOC_ENABLE_VERITY can fail with the following errors:
 - ``EKEYREJECTED``: the builtin signature doesn't match the file
 - ``EMSGSIZE``: the salt or builtin signature is too long
 - ``ENOKEY``: the ".fs-verity" keyring doesn't contain the certificate
   needed to verify the builtin signature
 - ``ENOPKG``: fs-verity recognizes the hash algorithm, but it's not
-  available in the kernel's crypto API as currently configured (e.g.
-  for SHA-512, missing CONFIG_CRYPTO_SHA512).
+  available in the kernel as currently configured
 - ``ENOTTY``: this type of filesystem does not implement fs-verity
 - ``EOPNOTSUPP``: the kernel was not configured with fs-verity
   support; or the filesystem superblock has not had the 'verity'
   feature enabled on it; or the filesystem does not support fs-verity
   on this file.  (See `Filesystem support`_.)
fs/verity/Kconfig +2 -4
index 40569d3527a71..76d1c5971b826 100644
@@ -1,14 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 
 config FS_VERITY
 	bool "FS Verity (read-only file-based authenticity protection)"
-	select CRYPTO
 	select CRYPTO_HASH_INFO
-	# SHA-256 is selected as it's intended to be the default hash algorithm.
-	# To avoid bloat, other wanted algorithms must be selected explicitly.
-	select CRYPTO_SHA256
+	select CRYPTO_LIB_SHA256
+	select CRYPTO_LIB_SHA512
 	help
 	  This option enables fs-verity.  fs-verity is the dm-verity
 	  mechanism implemented at the file level.  On supported
 	  filesystems (currently ext4, f2fs, and btrfs), userspace can
 	  use an ioctl to enable verity for a file, which causes the
fs/verity/enable.c +2 -6
index c284f46d1b535..0816ec295c380 100644
@@ -5,11 +5,10 @@
  * Copyright 2019 Google LLC
  */
 
 #include "fsverity_private.h"
 
-#include <crypto/hash.h>
 #include <linux/mount.h>
 #include <linux/sched/signal.h>
 #include <linux/uaccess.h>
 
 struct block_buffer {
@@ -22,11 +21,10 @@ struct block_buffer {
 static int hash_one_block(struct inode *inode,
 			  const struct merkle_tree_params *params,
 			  struct block_buffer *cur)
 {
 	struct block_buffer *next = cur + 1;
-	int err;
 
 	/*
 	 * Safety check to prevent a buffer overflow in case of a filesystem bug
 	 * that allows the file size to change despite deny_write_access(), or a
 	 * bug in the Merkle tree logic itself
@@ -35,14 +33,12 @@ static int hash_one_block(struct inode *inode,
 		return -EINVAL;
 
 	/* Zero-pad the block if it's shorter than the block size. */
 	memset(&cur->data[cur->filled], 0, params->block_size - cur->filled);
 
-	err = fsverity_hash_block(params, inode, cur->data,
-				  &next->data[next->filled]);
-	if (err)
-		return err;
+	fsverity_hash_block(params, inode, cur->data,
+			    &next->data[next->filled]);
 	next->filled += params->digest_size;
 	cur->filled = 0;
 	return 0;
 }
 
fs/verity/fsverity_private.h +15 -9
index b3506f56e180b..5fe854a5b9ad3 100644
@@ -18,25 +18,30 @@
  */
 #define FS_VERITY_MAX_LEVELS		8
 
 /* A hash algorithm supported by fs-verity */
 struct fsverity_hash_alg {
-	struct crypto_shash *tfm; /* hash tfm, allocated on demand */
 	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 */
 	/*
 	 * The HASH_ALGO_* constant for this algorithm.  This is different from
 	 * FS_VERITY_HASH_ALG_*, which uses a different numbering scheme.
 	 */
 	enum hash_algo algo_id;
 };
 
+union fsverity_hash_ctx {
+	struct sha256_ctx sha256;
+	struct sha512_ctx sha512;
+};
+
 /* Merkle tree parameters: hash algorithm, initial hash state, and topology */
 struct merkle_tree_params {
 	const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
-	const u8 *hashstate;		/* initial hash state or NULL */
+	/* initial hash state if salted, NULL if unsalted */
+	const union fsverity_hash_ctx *hashstate;
 	unsigned int digest_size;	/* same as hash_alg->digest_size */
 	unsigned int block_size;	/* size of data and tree blocks */
 	unsigned int hashes_per_block;	/* number of hashes per tree block */
 	unsigned int blocks_per_page;	/* PAGE_SIZE / block_size */
 	u8 log_digestsize;		/* log2(digest_size) */
@@ -74,20 +79,21 @@ struct fsverity_info {
 #define FS_VERITY_MAX_SIGNATURE_SIZE	(FS_VERITY_MAX_DESCRIPTOR_SIZE - \
 					 sizeof(struct fsverity_descriptor))
 
 /* hash_algs.c */
 
-extern struct fsverity_hash_alg fsverity_hash_algs[];
+extern const 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,
-				      const u8 *salt, size_t salt_size);
-int fsverity_hash_block(const struct merkle_tree_params *params,
-			const struct inode *inode, const void *data, u8 *out);
-int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
-			 const void *data, size_t size, u8 *out);
+union fsverity_hash_ctx *
+fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
+			    const u8 *salt, size_t salt_size);
+void fsverity_hash_block(const struct merkle_tree_params *params,
+			 const struct inode *inode, const void *data, u8 *out);
+void fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
+			  const void *data, size_t size, u8 *out);
 void __init fsverity_check_hash_algs(void);
 
 /* init.c */
 
 void __printf(3, 4) __cold
fs/verity/hash_algs.c +66 -128

274 lines not on this page · raw message

fs/verity/open.c +14 -22
index fdeb95eca3af3..0604cebe194cd 100644
@@ -40,22 +40,22 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
 	int level;
 
 	memset(params, 0, sizeof(*params));
 
 	hash_alg = fsverity_get_hash_alg(inode, hash_algorithm);
-	if (IS_ERR(hash_alg))
-		return PTR_ERR(hash_alg);
+	if (!hash_alg)
+		return -EINVAL;
 	params->hash_alg = hash_alg;
 	params->digest_size = hash_alg->digest_size;
 
-	params->hashstate = fsverity_prepare_hash_state(hash_alg, salt,
-							salt_size);
-	if (IS_ERR(params->hashstate)) {
-		err = PTR_ERR(params->hashstate);
-		params->hashstate = NULL;
-		fsverity_err(inode, "Error %d preparing hash state", err);
-		goto out_err;
+	if (salt_size) {
+		params->hashstate =
+			fsverity_prepare_hash_state(hash_alg, salt, salt_size);
+		if (!params->hashstate) {
+			err = -ENOMEM;
+			goto out_err;
+		}
 	}
 
 	/*
 	 * fs/verity/ directly assumes that the Merkle tree block size is a
 	 * power of 2 less than or equal to PAGE_SIZE.  Another restriction
@@ -156,22 +156,19 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
 
 /*
  * Compute the file digest by hashing the fsverity_descriptor excluding the
  * builtin signature and with the sig_size field set to 0.
  */
-static int compute_file_digest(const struct fsverity_hash_alg *hash_alg,
-			       struct fsverity_descriptor *desc,
-			       u8 *file_digest)
+static void compute_file_digest(const struct fsverity_hash_alg *hash_alg,
+				struct fsverity_descriptor *desc,
+				u8 *file_digest)
 {
 	__le32 sig_size = desc->sig_size;
-	int err;
 
 	desc->sig_size = 0;
-	err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest);
+	fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest);
 	desc->sig_size = sig_size;
-
-	return err;
 }
 
 /*
  * Create a new fsverity_info from the given fsverity_descriptor (with optional
  * appended builtin signature), and check the signature if present.  The
@@ -199,16 +196,11 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode,
 		goto fail;
 	}
 
 	memcpy(vi->root_hash, desc->root_hash, vi->tree_params.digest_size);
 
-	err = compute_file_digest(vi->tree_params.hash_alg, desc,
-				  vi->file_digest);
-	if (err) {
-		fsverity_err(inode, "Error %d computing file digest", err);
-		goto fail;
-	}
+	compute_file_digest(vi->tree_params.hash_alg, desc, vi->file_digest);
 
 	err = fsverity_verify_signature(vi, desc->signature,
 					le32_to_cpu(desc->sig_size));
 	if (err)
 		goto fail;
fs/verity/verify.c +2 -5
index 4fcad0825a120..481a381128cb9 100644
@@ -5,11 +5,10 @@
  * Copyright 2019 Google LLC
  */
 
 #include "fsverity_private.h"
 
-#include <crypto/hash.h>
 #include <linux/bio.h>
 
 static struct workqueue_struct *fsverity_read_workqueue;
 
 /*
@@ -200,12 +199,11 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
 		struct page *hpage = hblocks[level - 1].page;
 		const void *haddr = hblocks[level - 1].addr;
 		unsigned long hblock_idx = hblocks[level - 1].index;
 		unsigned int hoffset = hblocks[level - 1].hoffset;
 
-		if (fsverity_hash_block(params, inode, haddr, real_hash) != 0)
-			goto error;
+		fsverity_hash_block(params, inode, haddr, real_hash);
 		if (memcmp(want_hash, real_hash, hsize) != 0)
 			goto corrupted;
 		/*
 		 * Mark the hash block as verified.  This must be atomic and
 		 * idempotent, as the same hash block might be verified by
@@ -220,12 +218,11 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
 		kunmap_local(haddr);
 		put_page(hpage);
 	}
 
 	/* Finally, verify the data block. */
-	if (fsverity_hash_block(params, inode, data, real_hash) != 0)
-		goto error;
+	fsverity_hash_block(params, inode, data, real_hash);
 	if (memcmp(want_hash, real_hash, hsize) != 0)
 		goto corrupted;
 	return true;
 
 corrupted:
Signature · 1 line
2.50.0
maintainer Acked-by on the v1 series
#3 lore raw
In reply to Eric Biggers
Quoted 8 lines · Eric Biggers

This series, including all its prerequisites, is also available at:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git fsverity-libcrypto-v1

This series makes fs/verity/ use the SHA-2 library API instead of the old-school crypto API. This is simpler and more efficient.

Quoted 8 lines

This depends on my SHA-2 library improvements for 6.17 (many patches), so this patchset might need to wait until 6.18. But I'm also thinking about just basing the fsverity tree on libcrypto-next for 6.17.

Eric Biggers (2):
lib/crypto: hash_info: Move hash_info.c into lib/crypto/
fsverity: Switch from crypto_shash to SHA-2 library

Quoted 18 lines
 Documentation/filesystems/fsverity.rst |   3 +-
 crypto/Kconfig                         |   3 -
 crypto/Makefile                        |   1 -
 fs/verity/Kconfig                      |   6 +-
 fs/verity/enable.c                     |   8 +-
 fs/verity/fsverity_private.h           |  24 +--
 fs/verity/hash_algs.c                  | 194 +++++++++----------------
 fs/verity/open.c                       |  36 ++---
 fs/verity/verify.c                     |   7 +-
 lib/crypto/Kconfig                     |   3 +
 lib/crypto/Makefile                    |   2 +
 {crypto => lib/crypto}/hash_info.c     |   0
 12 files changed, 107 insertions(+), 180 deletions(-)
 rename {crypto => lib/crypto}/hash_info.c (100%)

--
2.50.0

author maintainer
#4 lore raw
In reply to Eric Biggers
Quoted 7 lines · Eric Biggers

This series, including all its prerequisites, is also available at:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git fsverity-libcrypto-v1

This series makes fs/verity/ use the SHA-2 library API instead of the old-school crypto API. This is simpler and more efficient.

Quoted 7 lines

This depends on my SHA-2 library improvements for 6.17 (many patches), so this patchset might need to wait until 6.18. But I'm also thinking about just basing the fsverity tree on libcrypto-next for 6.17.

Eric Biggers (2):
lib/crypto: hash_info: Move hash_info.c into lib/crypto/
fsverity: Switch from crypto_shash to SHA-2 library

FYI, I've applied this series to
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next
so that it gets linux-next coverage.

As mentioned, it depends on the SHA-256 and SHA-512 improvements in lib/crypto/. But Linus has also expressed a preference to not put too much in one pull request.

My current plan is to do 3 pull requests:

1. "Crypto library updates" - most patches, mainly SHA-256 and SHA-512 library improvements

2. "Crypto library tests" - based on (1) but adds:
lib/crypto: tests: Add hash-test-template.h and gen-hash-testvecs.py lib/crypto: tests: Add KUnit tests for SHA-224 and SHA-256 lib/crypto: tests: Add KUnit tests for SHA-384 and SHA-512 lib/crypto: tests: Add KUnit tests for Poly1305

3. "Crypto library conversions" - based on (1) but adds:
apparmor: use SHA-256 library API instead of crypto_shash API
fsverity: Explicitly include <linux/export.h>
fsverity: Switch from crypto_shash to SHA-2 library

I'll put all of these in libcrypto-next for linux-next coverage, but (3) will have a slightly different base commit in the final version.

- Eric

author maintainer
#5 lore raw
Quoted 35 lines · Eric Biggers
Quoted 7 lines · Eric Biggers

This series, including all its prerequisites, is also available at:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git fsverity-libcrypto-v1

This series makes fs/verity/ use the SHA-2 library API instead of the old-school crypto API. This is simpler and more efficient.

Quoted 7 lines

This depends on my SHA-2 library improvements for 6.17 (many patches), so this patchset might need to wait until 6.18. But I'm also thinking about just basing the fsverity tree on libcrypto-next for 6.17.

Eric Biggers (2):
lib/crypto: hash_info: Move hash_info.c into lib/crypto/
fsverity: Switch from crypto_shash to SHA-2 library

FYI, I've applied this series to
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next
so that it gets linux-next coverage.

As mentioned, it depends on the SHA-256 and SHA-512 improvements in lib/crypto/. But Linus has also expressed a preference to not put too much in one pull request.

My current plan is to do 3 pull requests:

1. "Crypto library updates" - most patches, mainly SHA-256 and SHA-512 library improvements

2. "Crypto library tests" - based on (1) but adds:
lib/crypto: tests: Add hash-test-template.h and gen-hash-testvecs.py lib/crypto: tests: Add KUnit tests for SHA-224 and SHA-256 lib/crypto: tests: Add KUnit tests for SHA-384 and SHA-512 lib/crypto: tests: Add KUnit tests for Poly1305

Quoted 7 lines

3. "Crypto library conversions" - based on (1) but adds:
apparmor: use SHA-256 library API instead of crypto_shash API
fsverity: Explicitly include <linux/export.h>
fsverity: Switch from crypto_shash to SHA-2 library

I'll put all of these in libcrypto-next for linux-next coverage, but (3) will have a slightly different base commit in the final version.

Correction: everything can have the same commit ID in libcrypto-next as in the final pull requests, if I put (2) and (3) on their own branches and merge them together. I've done that.

- Eric