Skip to content

Commit bdf253d

Browse files
Eric BiggersMikulas Patocka
authored andcommitted
dm-verity: remove support for asynchronous hashes
The support for asynchronous hashes in dm-verity has outlived its usefulness. It adds significant code complexity and opportunity for bugs. I don't know of anyone using it in practice. (The original submitter of the code possibly was, but that was 8 years ago.) Data I recently collected for en/decryption shows that using off-CPU crypto "accelerators" is consistently much slower than the CPU (https://lore.kernel.org/r/[email protected]/), even on CPUs that lack dedicated cryptographic instructions. Similar results are likely to be seen for hashing. I already removed support for asynchronous hashes from fsverity two years ago, and no one ever complained. Moreover, neither dm-verity, fsverity, nor fscrypt has ever actually used the asynchronous crypto algorithms in a truly asynchronous manner. The lack of interest in such optimizations provides further evidence that it's only the CPU-based crypto that actually matters. Historically, it's also been common for people to forget to enable the optimized SHA-256 code, which could contribute to an off-CPU crypto engine being perceived as more useful than it really is. In 6.16 I fixed that: the optimized SHA-256 code is now enabled by default. Therefore, let's drop the support for asynchronous hashes in dm-verity. Tested with verity-compat-test. Acked-by: Ard Biesheuvel <[email protected]> Signed-off-by: Eric Biggers <[email protected]> Signed-off-by: Mikulas Patocka <[email protected]>
1 parent 6e11952 commit bdf253d

File tree

3 files changed

+38
-173
lines changed

3 files changed

+38
-173
lines changed

drivers/md/dm-verity-fec.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
191191
u8 *want_digest, u8 *data)
192192
{
193193
if (unlikely(verity_hash(v, io, data, 1 << v->data_dev_block_bits,
194-
verity_io_real_digest(v, io), true)))
194+
verity_io_real_digest(v, io))))
195195
return 0;
196196

197197
return memcmp(verity_io_real_digest(v, io), want_digest,
@@ -392,7 +392,7 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
392392

393393
/* Always re-validate the corrected block against the expected hash */
394394
r = verity_hash(v, io, fio->output, 1 << v->data_dev_block_bits,
395-
verity_io_real_digest(v, io), true);
395+
verity_io_real_digest(v, io));
396396
if (unlikely(r < 0))
397397
return r;
398398

drivers/md/dm-verity-target.c

Lines changed: 29 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "dm-audit.h"
2020
#include <linux/module.h>
2121
#include <linux/reboot.h>
22-
#include <linux/scatterlist.h>
2322
#include <linux/string.h>
2423
#include <linux/jump_label.h>
2524
#include <linux/security.h>
@@ -61,9 +60,6 @@ module_param_array_named(use_bh_bytes, dm_verity_use_bh_bytes, uint, NULL, 0644)
6160

6261
static DEFINE_STATIC_KEY_FALSE(use_bh_wq_enabled);
6362

64-
/* Is at least one dm-verity instance using ahash_tfm instead of shash_tfm? */
65-
static DEFINE_STATIC_KEY_FALSE(ahash_enabled);
66-
6763
struct dm_verity_prefetch_work {
6864
struct work_struct work;
6965
struct dm_verity *v;
@@ -118,100 +114,21 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
118114
return block >> (level * v->hash_per_block_bits);
119115
}
120116

121-
static int verity_ahash_update(struct dm_verity *v, struct ahash_request *req,
122-
const u8 *data, size_t len,
123-
struct crypto_wait *wait)
124-
{
125-
struct scatterlist sg;
126-
127-
if (likely(!is_vmalloc_addr(data))) {
128-
sg_init_one(&sg, data, len);
129-
ahash_request_set_crypt(req, &sg, NULL, len);
130-
return crypto_wait_req(crypto_ahash_update(req), wait);
131-
}
132-
133-
do {
134-
int r;
135-
size_t this_step = min_t(size_t, len, PAGE_SIZE - offset_in_page(data));
136-
137-
flush_kernel_vmap_range((void *)data, this_step);
138-
sg_init_table(&sg, 1);
139-
sg_set_page(&sg, vmalloc_to_page(data), this_step, offset_in_page(data));
140-
ahash_request_set_crypt(req, &sg, NULL, this_step);
141-
r = crypto_wait_req(crypto_ahash_update(req), wait);
142-
if (unlikely(r))
143-
return r;
144-
data += this_step;
145-
len -= this_step;
146-
} while (len);
147-
148-
return 0;
149-
}
150-
151-
/*
152-
* Wrapper for crypto_ahash_init, which handles verity salting.
153-
*/
154-
static int verity_ahash_init(struct dm_verity *v, struct ahash_request *req,
155-
struct crypto_wait *wait, bool may_sleep)
156-
{
157-
int r;
158-
159-
ahash_request_set_tfm(req, v->ahash_tfm);
160-
ahash_request_set_callback(req,
161-
may_sleep ? CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG : 0,
162-
crypto_req_done, (void *)wait);
163-
crypto_init_wait(wait);
164-
165-
r = crypto_wait_req(crypto_ahash_init(req), wait);
166-
167-
if (unlikely(r < 0)) {
168-
if (r != -ENOMEM)
169-
DMERR("crypto_ahash_init failed: %d", r);
170-
return r;
171-
}
172-
173-
if (likely(v->salt_size && (v->version >= 1)))
174-
r = verity_ahash_update(v, req, v->salt, v->salt_size, wait);
175-
176-
return r;
177-
}
178-
179-
static int verity_ahash_final(struct dm_verity *v, struct ahash_request *req,
180-
u8 *digest, struct crypto_wait *wait)
181-
{
182-
int r;
183-
184-
if (unlikely(v->salt_size && (!v->version))) {
185-
r = verity_ahash_update(v, req, v->salt, v->salt_size, wait);
186-
187-
if (r < 0) {
188-
DMERR("%s failed updating salt: %d", __func__, r);
189-
goto out;
190-
}
191-
}
192-
193-
ahash_request_set_crypt(req, NULL, digest, 0);
194-
r = crypto_wait_req(crypto_ahash_final(req), wait);
195-
out:
196-
return r;
197-
}
198-
199117
int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
200-
const u8 *data, size_t len, u8 *digest, bool may_sleep)
118+
const u8 *data, size_t len, u8 *digest)
201119
{
120+
struct shash_desc *desc = &io->hash_desc;
202121
int r;
203122

204-
if (static_branch_unlikely(&ahash_enabled) && !v->shash_tfm) {
205-
struct ahash_request *req = verity_io_hash_req(v, io);
206-
struct crypto_wait wait;
207-
208-
r = verity_ahash_init(v, req, &wait, may_sleep) ?:
209-
verity_ahash_update(v, req, data, len, &wait) ?:
210-
verity_ahash_final(v, req, digest, &wait);
123+
desc->tfm = v->shash_tfm;
124+
if (unlikely(v->initial_hashstate == NULL)) {
125+
/* Version 0: salt at end */
126+
r = crypto_shash_init(desc) ?:
127+
crypto_shash_update(desc, data, len) ?:
128+
crypto_shash_update(desc, v->salt, v->salt_size) ?:
129+
crypto_shash_final(desc, digest);
211130
} else {
212-
struct shash_desc *desc = verity_io_hash_req(v, io);
213-
214-
desc->tfm = v->shash_tfm;
131+
/* Version 1: salt at beginning */
215132
r = crypto_shash_import(desc, v->initial_hashstate) ?:
216133
crypto_shash_finup(desc, data, len, digest);
217134
}
@@ -362,7 +279,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
362279
}
363280

364281
r = verity_hash(v, io, data, 1 << v->hash_dev_block_bits,
365-
verity_io_real_digest(v, io), !io->in_bh);
282+
verity_io_real_digest(v, io));
366283
if (unlikely(r < 0))
367284
goto release_ret_r;
368285

@@ -465,7 +382,7 @@ static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
465382
goto free_ret;
466383

467384
r = verity_hash(v, io, buffer, 1 << v->data_dev_block_bits,
468-
verity_io_real_digest(v, io), true);
385+
verity_io_real_digest(v, io));
469386
if (unlikely(r))
470387
goto free_ret;
471388

@@ -581,7 +498,7 @@ static int verity_verify_io(struct dm_verity_io *io)
581498
}
582499

583500
r = verity_hash(v, io, data, block_size,
584-
verity_io_real_digest(v, io), !io->in_bh);
501+
verity_io_real_digest(v, io));
585502
if (unlikely(r < 0)) {
586503
kunmap_local(data);
587504
return r;
@@ -1092,12 +1009,7 @@ static void verity_dtr(struct dm_target *ti)
10921009
kfree(v->zero_digest);
10931010
verity_free_sig(v);
10941011

1095-
if (v->ahash_tfm) {
1096-
static_branch_dec(&ahash_enabled);
1097-
crypto_free_ahash(v->ahash_tfm);
1098-
} else {
1099-
crypto_free_shash(v->shash_tfm);
1100-
}
1012+
crypto_free_shash(v->shash_tfm);
11011013

11021014
kfree(v->alg_name);
11031015

@@ -1157,7 +1069,8 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
11571069
if (!v->zero_digest)
11581070
return r;
11591071

1160-
io = kmalloc(sizeof(*io) + v->hash_reqsize, GFP_KERNEL);
1072+
io = kmalloc(sizeof(*io) + crypto_shash_descsize(v->shash_tfm),
1073+
GFP_KERNEL);
11611074

11621075
if (!io)
11631076
return r; /* verity_dtr will free zero_digest */
@@ -1168,7 +1081,7 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
11681081
goto out;
11691082

11701083
r = verity_hash(v, io, zero_data, 1 << v->data_dev_block_bits,
1171-
v->zero_digest, true);
1084+
v->zero_digest);
11721085

11731086
out:
11741087
kfree(io);
@@ -1324,60 +1237,22 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
13241237
static int verity_setup_hash_alg(struct dm_verity *v, const char *alg_name)
13251238
{
13261239
struct dm_target *ti = v->ti;
1327-
struct crypto_ahash *ahash;
1328-
struct crypto_shash *shash = NULL;
1329-
const char *driver_name;
1240+
struct crypto_shash *shash;
13301241

13311242
v->alg_name = kstrdup(alg_name, GFP_KERNEL);
13321243
if (!v->alg_name) {
13331244
ti->error = "Cannot allocate algorithm name";
13341245
return -ENOMEM;
13351246
}
13361247

1337-
/*
1338-
* Allocate the hash transformation object that this dm-verity instance
1339-
* will use. The vast majority of dm-verity users use CPU-based
1340-
* hashing, so when possible use the shash API to minimize the crypto
1341-
* API overhead. If the ahash API resolves to a different driver
1342-
* (likely an off-CPU hardware offload), use ahash instead. Also use
1343-
* ahash if the obsolete dm-verity format with the appended salt is
1344-
* being used, so that quirk only needs to be handled in one place.
1345-
*/
1346-
ahash = crypto_alloc_ahash(alg_name, 0,
1347-
v->use_bh_wq ? CRYPTO_ALG_ASYNC : 0);
1348-
if (IS_ERR(ahash)) {
1248+
shash = crypto_alloc_shash(alg_name, 0, 0);
1249+
if (IS_ERR(shash)) {
13491250
ti->error = "Cannot initialize hash function";
1350-
return PTR_ERR(ahash);
1351-
}
1352-
driver_name = crypto_ahash_driver_name(ahash);
1353-
if (v->version >= 1 /* salt prepended, not appended? */) {
1354-
shash = crypto_alloc_shash(alg_name, 0, 0);
1355-
if (!IS_ERR(shash) &&
1356-
strcmp(crypto_shash_driver_name(shash), driver_name) != 0) {
1357-
/*
1358-
* ahash gave a different driver than shash, so probably
1359-
* this is a case of real hardware offload. Use ahash.
1360-
*/
1361-
crypto_free_shash(shash);
1362-
shash = NULL;
1363-
}
1364-
}
1365-
if (!IS_ERR_OR_NULL(shash)) {
1366-
crypto_free_ahash(ahash);
1367-
ahash = NULL;
1368-
v->shash_tfm = shash;
1369-
v->digest_size = crypto_shash_digestsize(shash);
1370-
v->hash_reqsize = sizeof(struct shash_desc) +
1371-
crypto_shash_descsize(shash);
1372-
DMINFO("%s using shash \"%s\"", alg_name, driver_name);
1373-
} else {
1374-
v->ahash_tfm = ahash;
1375-
static_branch_inc(&ahash_enabled);
1376-
v->digest_size = crypto_ahash_digestsize(ahash);
1377-
v->hash_reqsize = sizeof(struct ahash_request) +
1378-
crypto_ahash_reqsize(ahash);
1379-
DMINFO("%s using ahash \"%s\"", alg_name, driver_name);
1251+
return PTR_ERR(shash);
13801252
}
1253+
v->shash_tfm = shash;
1254+
v->digest_size = crypto_shash_digestsize(shash);
1255+
DMINFO("%s using \"%s\"", alg_name, crypto_shash_driver_name(shash));
13811256
if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
13821257
ti->error = "Digest size too big";
13831258
return -EINVAL;
@@ -1402,7 +1277,7 @@ static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg)
14021277
return -EINVAL;
14031278
}
14041279
}
1405-
if (v->shash_tfm) {
1280+
if (v->version) { /* Version 1: salt at beginning */
14061281
SHASH_DESC_ON_STACK(desc, v->shash_tfm);
14071282
int r;
14081283

@@ -1681,7 +1556,8 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
16811556
goto bad;
16821557
}
16831558

1684-
ti->per_io_data_size = sizeof(struct dm_verity_io) + v->hash_reqsize;
1559+
ti->per_io_data_size = sizeof(struct dm_verity_io) +
1560+
crypto_shash_descsize(v->shash_tfm);
16851561

16861562
r = verity_fec_ctr(v);
16871563
if (r)
@@ -1788,10 +1664,7 @@ static int verity_preresume(struct dm_target *ti)
17881664
bdev = dm_disk(dm_table_get_md(ti->table))->part0;
17891665
root_digest.digest = v->root_digest;
17901666
root_digest.digest_len = v->digest_size;
1791-
if (static_branch_unlikely(&ahash_enabled) && !v->shash_tfm)
1792-
root_digest.alg = crypto_ahash_alg_name(v->ahash_tfm);
1793-
else
1794-
root_digest.alg = crypto_shash_alg_name(v->shash_tfm);
1667+
root_digest.alg = crypto_shash_alg_name(v->shash_tfm);
17951668

17961669
r = security_bdev_setintegrity(bdev, LSM_INT_DMVERITY_ROOTHASH, &root_digest,
17971670
sizeof(root_digest));
@@ -1817,7 +1690,7 @@ static struct target_type verity_target = {
18171690
.name = "verity",
18181691
/* Note: the LSMs depend on the singleton and immutable features */
18191692
.features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE,
1820-
.version = {1, 11, 0},
1693+
.version = {1, 12, 0},
18211694
.module = THIS_MODULE,
18221695
.ctr = verity_ctr,
18231696
.dtr = verity_dtr,

drivers/md/dm-verity.h

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,10 @@ struct dm_verity {
3939
struct dm_target *ti;
4040
struct dm_bufio_client *bufio;
4141
char *alg_name;
42-
struct crypto_ahash *ahash_tfm; /* either this or shash_tfm is set */
43-
struct crypto_shash *shash_tfm; /* either this or ahash_tfm is set */
42+
struct crypto_shash *shash_tfm;
4443
u8 *root_digest; /* digest of the root block */
4544
u8 *salt; /* salt: its size is salt_size */
46-
u8 *initial_hashstate; /* salted initial state, if shash_tfm is set */
45+
u8 *initial_hashstate; /* salted initial state, if version >= 1 */
4746
u8 *zero_digest; /* digest for a zero block */
4847
#ifdef CONFIG_SECURITY
4948
u8 *root_digest_sig; /* signature of the root digest */
@@ -61,7 +60,6 @@ struct dm_verity {
6160
bool hash_failed:1; /* set if hash of any block failed */
6261
bool use_bh_wq:1; /* try to verify in BH wq before normal work-queue */
6362
unsigned int digest_size; /* digest size for the current hash algorithm */
64-
unsigned int hash_reqsize; /* the size of temporary space for crypto */
6563
enum verity_mode mode; /* mode for handling verification errors */
6664
enum verity_mode error_mode;/* mode for handling I/O errors */
6765
unsigned int corrupted_errs;/* Number of errors for corrupted blocks */
@@ -100,19 +98,13 @@ struct dm_verity_io {
10098
u8 want_digest[HASH_MAX_DIGESTSIZE];
10199

102100
/*
103-
* This struct is followed by a variable-sized hash request of size
104-
* v->hash_reqsize, either a struct ahash_request or a struct shash_desc
105-
* (depending on whether ahash_tfm or shash_tfm is being used). To
106-
* access it, use verity_io_hash_req().
101+
* Temporary space for hashing. This is variable-length and must be at
102+
* the end of the struct. struct shash_desc is just the fixed part;
103+
* it's followed by a context of size crypto_shash_descsize(shash_tfm).
107104
*/
105+
struct shash_desc hash_desc;
108106
};
109107

110-
static inline void *verity_io_hash_req(struct dm_verity *v,
111-
struct dm_verity_io *io)
112-
{
113-
return io + 1;
114-
}
115-
116108
static inline u8 *verity_io_real_digest(struct dm_verity *v,
117109
struct dm_verity_io *io)
118110
{
@@ -126,7 +118,7 @@ static inline u8 *verity_io_want_digest(struct dm_verity *v,
126118
}
127119

128120
extern int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
129-
const u8 *data, size_t len, u8 *digest, bool may_sleep);
121+
const u8 *data, size_t len, u8 *digest);
130122

131123
extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
132124
sector_t block, u8 *digest, bool *is_zero);

0 commit comments

Comments
 (0)