Skip to content

Commit 4b65b85

Browse files
committed
Merge tag 'libcrypto-conversions-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux
Pull crypto library conversions from Eric Biggers: "Convert fsverity and apparmor to use the SHA-2 library functions instead of crypto_shash. This is simpler and also slightly faster" * tag 'libcrypto-conversions-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux: fsverity: Switch from crypto_shash to SHA-2 library fsverity: Explicitly include <linux/export.h> apparmor: use SHA-256 library API instead of crypto_shash API
2 parents f2f573e + 998646b commit 4b65b85

11 files changed

Lines changed: 120 additions & 251 deletions

File tree

Documentation/filesystems/fsverity.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,7 @@ FS_IOC_ENABLE_VERITY can fail with the following errors:
185185
- ``ENOKEY``: the ".fs-verity" keyring doesn't contain the certificate
186186
needed to verify the builtin signature
187187
- ``ENOPKG``: fs-verity recognizes the hash algorithm, but it's not
188-
available in the kernel's crypto API as currently configured (e.g.
189-
for SHA-512, missing CONFIG_CRYPTO_SHA512).
188+
available in the kernel as currently configured
190189
- ``ENOTTY``: this type of filesystem does not implement fs-verity
191190
- ``EOPNOTSUPP``: the kernel was not configured with fs-verity
192191
support; or the filesystem superblock has not had the 'verity'

fs/verity/Kconfig

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
config FS_VERITY
44
bool "FS Verity (read-only file-based authenticity protection)"
5-
select CRYPTO
65
select CRYPTO_HASH_INFO
7-
# SHA-256 is selected as it's intended to be the default hash algorithm.
8-
# To avoid bloat, other wanted algorithms must be selected explicitly.
9-
select CRYPTO_SHA256
6+
select CRYPTO_LIB_SHA256
7+
select CRYPTO_LIB_SHA512
108
help
119
This option enables fs-verity. fs-verity is the dm-verity
1210
mechanism implemented at the file level. On supported

fs/verity/enable.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
#include "fsverity_private.h"
99

10-
#include <crypto/hash.h>
10+
#include <linux/export.h>
1111
#include <linux/mount.h>
1212
#include <linux/sched/signal.h>
1313
#include <linux/uaccess.h>
@@ -24,7 +24,6 @@ static int hash_one_block(struct inode *inode,
2424
struct block_buffer *cur)
2525
{
2626
struct block_buffer *next = cur + 1;
27-
int err;
2827

2928
/*
3029
* Safety check to prevent a buffer overflow in case of a filesystem bug
@@ -37,10 +36,8 @@ static int hash_one_block(struct inode *inode,
3736
/* Zero-pad the block if it's shorter than the block size. */
3837
memset(&cur->data[cur->filled], 0, params->block_size - cur->filled);
3938

40-
err = fsverity_hash_block(params, inode, cur->data,
41-
&next->data[next->filled]);
42-
if (err)
43-
return err;
39+
fsverity_hash_block(params, inode, cur->data,
40+
&next->data[next->filled]);
4441
next->filled += params->digest_size;
4542
cur->filled = 0;
4643
return 0;

fs/verity/fsverity_private.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
/* A hash algorithm supported by fs-verity */
2222
struct fsverity_hash_alg {
23-
struct crypto_shash *tfm; /* hash tfm, allocated on demand */
2423
const char *name; /* crypto API name, e.g. sha256 */
2524
unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
2625
unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */
@@ -31,10 +30,16 @@ struct fsverity_hash_alg {
3130
enum hash_algo algo_id;
3231
};
3332

33+
union fsverity_hash_ctx {
34+
struct sha256_ctx sha256;
35+
struct sha512_ctx sha512;
36+
};
37+
3438
/* Merkle tree parameters: hash algorithm, initial hash state, and topology */
3539
struct merkle_tree_params {
3640
const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
37-
const u8 *hashstate; /* initial hash state or NULL */
41+
/* initial hash state if salted, NULL if unsalted */
42+
const union fsverity_hash_ctx *hashstate;
3843
unsigned int digest_size; /* same as hash_alg->digest_size */
3944
unsigned int block_size; /* size of data and tree blocks */
4045
unsigned int hashes_per_block; /* number of hashes per tree block */
@@ -76,16 +81,17 @@ struct fsverity_info {
7681

7782
/* hash_algs.c */
7883

79-
extern struct fsverity_hash_alg fsverity_hash_algs[];
84+
extern const struct fsverity_hash_alg fsverity_hash_algs[];
8085

8186
const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
8287
unsigned int num);
83-
const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
84-
const u8 *salt, size_t salt_size);
85-
int fsverity_hash_block(const struct merkle_tree_params *params,
86-
const struct inode *inode, const void *data, u8 *out);
87-
int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
88-
const void *data, size_t size, u8 *out);
88+
union fsverity_hash_ctx *
89+
fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
90+
const u8 *salt, size_t salt_size);
91+
void fsverity_hash_block(const struct merkle_tree_params *params,
92+
const struct inode *inode, const void *data, u8 *out);
93+
void fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
94+
const void *data, size_t size, u8 *out);
8995
void __init fsverity_check_hash_algs(void);
9096

9197
/* init.c */

fs/verity/hash_algs.c

Lines changed: 66 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77

88
#include "fsverity_private.h"
99

10-
#include <crypto/hash.h>
11-
1210
/* The hash algorithms supported by fs-verity */
13-
struct fsverity_hash_alg fsverity_hash_algs[] = {
11+
const struct fsverity_hash_alg fsverity_hash_algs[] = {
1412
[FS_VERITY_HASH_ALG_SHA256] = {
1513
.name = "sha256",
1614
.digest_size = SHA256_DIGEST_SIZE,
@@ -25,106 +23,42 @@ struct fsverity_hash_alg fsverity_hash_algs[] = {
2523
},
2624
};
2725

28-
static DEFINE_MUTEX(fsverity_hash_alg_init_mutex);
29-
3026
/**
31-
* fsverity_get_hash_alg() - validate and prepare a hash algorithm
27+
* fsverity_get_hash_alg() - get a hash algorithm by number
3228
* @inode: optional inode for logging purposes
3329
* @num: the hash algorithm number
3430
*
35-
* Get the struct fsverity_hash_alg for the given hash algorithm number, and
36-
* ensure it has a hash transform ready to go. The hash transforms are
37-
* allocated on-demand so that we don't waste resources unnecessarily, and
38-
* because the crypto modules may be initialized later than fs/verity/.
31+
* Get the struct fsverity_hash_alg for the given hash algorithm number.
3932
*
40-
* Return: pointer to the hash alg on success, else an ERR_PTR()
33+
* Return: pointer to the hash alg if it's known, otherwise NULL.
4134
*/
4235
const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
4336
unsigned int num)
4437
{
45-
struct fsverity_hash_alg *alg;
46-
struct crypto_shash *tfm;
47-
int err;
48-
4938
if (num >= ARRAY_SIZE(fsverity_hash_algs) ||
5039
!fsverity_hash_algs[num].name) {
5140
fsverity_warn(inode, "Unknown hash algorithm number: %u", num);
52-
return ERR_PTR(-EINVAL);
53-
}
54-
alg = &fsverity_hash_algs[num];
55-
56-
/* pairs with smp_store_release() below */
57-
if (likely(smp_load_acquire(&alg->tfm) != NULL))
58-
return alg;
59-
60-
mutex_lock(&fsverity_hash_alg_init_mutex);
61-
62-
if (alg->tfm != NULL)
63-
goto out_unlock;
64-
65-
tfm = crypto_alloc_shash(alg->name, 0, 0);
66-
if (IS_ERR(tfm)) {
67-
if (PTR_ERR(tfm) == -ENOENT) {
68-
fsverity_warn(inode,
69-
"Missing crypto API support for hash algorithm \"%s\"",
70-
alg->name);
71-
alg = ERR_PTR(-ENOPKG);
72-
goto out_unlock;
73-
}
74-
fsverity_err(inode,
75-
"Error allocating hash algorithm \"%s\": %ld",
76-
alg->name, PTR_ERR(tfm));
77-
alg = ERR_CAST(tfm);
78-
goto out_unlock;
41+
return NULL;
7942
}
80-
81-
err = -EINVAL;
82-
if (WARN_ON_ONCE(alg->digest_size != crypto_shash_digestsize(tfm)))
83-
goto err_free_tfm;
84-
if (WARN_ON_ONCE(alg->block_size != crypto_shash_blocksize(tfm)))
85-
goto err_free_tfm;
86-
87-
pr_info("%s using implementation \"%s\"\n",
88-
alg->name, crypto_shash_driver_name(tfm));
89-
90-
/* pairs with smp_load_acquire() above */
91-
smp_store_release(&alg->tfm, tfm);
92-
goto out_unlock;
93-
94-
err_free_tfm:
95-
crypto_free_shash(tfm);
96-
alg = ERR_PTR(err);
97-
out_unlock:
98-
mutex_unlock(&fsverity_hash_alg_init_mutex);
99-
return alg;
43+
return &fsverity_hash_algs[num];
10044
}
10145

10246
/**
10347
* fsverity_prepare_hash_state() - precompute the initial hash state
10448
* @alg: hash algorithm
10549
* @salt: a salt which is to be prepended to all data to be hashed
106-
* @salt_size: salt size in bytes, possibly 0
50+
* @salt_size: salt size in bytes
10751
*
108-
* Return: NULL if the salt is empty, otherwise the kmalloc()'ed precomputed
109-
* initial hash state on success or an ERR_PTR() on failure.
52+
* Return: the kmalloc()'ed initial hash state, or NULL if out of memory.
11053
*/
111-
const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
112-
const u8 *salt, size_t salt_size)
54+
union fsverity_hash_ctx *
55+
fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
56+
const u8 *salt, size_t salt_size)
11357
{
114-
u8 *hashstate = NULL;
115-
SHASH_DESC_ON_STACK(desc, alg->tfm);
11658
u8 *padded_salt = NULL;
11759
size_t padded_salt_size;
118-
int err;
119-
120-
desc->tfm = alg->tfm;
121-
122-
if (salt_size == 0)
123-
return NULL;
124-
125-
hashstate = kmalloc(crypto_shash_statesize(alg->tfm), GFP_KERNEL);
126-
if (!hashstate)
127-
return ERR_PTR(-ENOMEM);
60+
union fsverity_hash_ctx ctx;
61+
void *res = NULL;
12862

12963
/*
13064
* Zero-pad the salt to the next multiple of the input size of the hash
@@ -135,30 +69,26 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
13569
*/
13670
padded_salt_size = round_up(salt_size, alg->block_size);
13771
padded_salt = kzalloc(padded_salt_size, GFP_KERNEL);
138-
if (!padded_salt) {
139-
err = -ENOMEM;
140-
goto err_free;
141-
}
72+
if (!padded_salt)
73+
return NULL;
14274
memcpy(padded_salt, salt, salt_size);
143-
err = crypto_shash_init(desc);
144-
if (err)
145-
goto err_free;
146-
147-
err = crypto_shash_update(desc, padded_salt, padded_salt_size);
148-
if (err)
149-
goto err_free;
150-
151-
err = crypto_shash_export(desc, hashstate);
152-
if (err)
153-
goto err_free;
154-
out:
155-
kfree(padded_salt);
156-
return hashstate;
15775

158-
err_free:
159-
kfree(hashstate);
160-
hashstate = ERR_PTR(err);
161-
goto out;
76+
switch (alg->algo_id) {
77+
case HASH_ALGO_SHA256:
78+
sha256_init(&ctx.sha256);
79+
sha256_update(&ctx.sha256, padded_salt, padded_salt_size);
80+
res = kmemdup(&ctx.sha256, sizeof(ctx.sha256), GFP_KERNEL);
81+
break;
82+
case HASH_ALGO_SHA512:
83+
sha512_init(&ctx.sha512);
84+
sha512_update(&ctx.sha512, padded_salt, padded_salt_size);
85+
res = kmemdup(&ctx.sha512, sizeof(ctx.sha512), GFP_KERNEL);
86+
break;
87+
default:
88+
WARN_ON_ONCE(1);
89+
}
90+
kfree(padded_salt);
91+
return res;
16292
}
16393

16494
/**
@@ -170,31 +100,32 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
170100
*
171101
* Hash a single data or hash block. The hash is salted if a salt is specified
172102
* in the Merkle tree parameters.
173-
*
174-
* Return: 0 on success, -errno on failure
175103
*/
176-
int fsverity_hash_block(const struct merkle_tree_params *params,
177-
const struct inode *inode, const void *data, u8 *out)
104+
void fsverity_hash_block(const struct merkle_tree_params *params,
105+
const struct inode *inode, const void *data, u8 *out)
178106
{
179-
SHASH_DESC_ON_STACK(desc, params->hash_alg->tfm);
180-
int err;
181-
182-
desc->tfm = params->hash_alg->tfm;
183-
184-
if (params->hashstate) {
185-
err = crypto_shash_import(desc, params->hashstate);
186-
if (err) {
187-
fsverity_err(inode,
188-
"Error %d importing hash state", err);
189-
return err;
190-
}
191-
err = crypto_shash_finup(desc, data, params->block_size, out);
192-
} else {
193-
err = crypto_shash_digest(desc, data, params->block_size, out);
107+
union fsverity_hash_ctx ctx;
108+
109+
if (!params->hashstate) {
110+
fsverity_hash_buffer(params->hash_alg, data, params->block_size,
111+
out);
112+
return;
113+
}
114+
115+
switch (params->hash_alg->algo_id) {
116+
case HASH_ALGO_SHA256:
117+
ctx.sha256 = params->hashstate->sha256;
118+
sha256_update(&ctx.sha256, data, params->block_size);
119+
sha256_final(&ctx.sha256, out);
120+
return;
121+
case HASH_ALGO_SHA512:
122+
ctx.sha512 = params->hashstate->sha512;
123+
sha512_update(&ctx.sha512, data, params->block_size);
124+
sha512_final(&ctx.sha512, out);
125+
return;
126+
default:
127+
BUG();
194128
}
195-
if (err)
196-
fsverity_err(inode, "Error %d computing block hash", err);
197-
return err;
198129
}
199130

200131
/**
@@ -203,13 +134,20 @@ int fsverity_hash_block(const struct merkle_tree_params *params,
203134
* @data: the data to hash
204135
* @size: size of data to hash, in bytes
205136
* @out: output digest, size 'alg->digest_size' bytes
206-
*
207-
* Return: 0 on success, -errno on failure
208137
*/
209-
int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
210-
const void *data, size_t size, u8 *out)
138+
void fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
139+
const void *data, size_t size, u8 *out)
211140
{
212-
return crypto_shash_tfm_digest(alg->tfm, data, size, out);
141+
switch (alg->algo_id) {
142+
case HASH_ALGO_SHA256:
143+
sha256(data, size, out);
144+
return;
145+
case HASH_ALGO_SHA512:
146+
sha512(data, size, out);
147+
return;
148+
default:
149+
BUG();
150+
}
213151
}
214152

215153
void __init fsverity_check_hash_algs(void)

fs/verity/measure.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/bpf.h>
1111
#include <linux/btf.h>
12+
#include <linux/export.h>
1213
#include <linux/uaccess.h>
1314

1415
/**

0 commit comments

Comments
 (0)