]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dm-verity: reduce scope of real and wanted digests
authorEric Biggers <ebiggers@kernel.org>
Tue, 14 Oct 2025 21:16:56 +0000 (14:16 -0700)
committerMikulas Patocka <mpatocka@redhat.com>
Mon, 20 Oct 2025 13:47:35 +0000 (15:47 +0200)
In preparation for supporting interleaved hashing where dm-verity will
need to keep track of the real and wanted digests for multiple data
blocks simultaneously, stop using the want_digest and real_digest fields
of struct dm_verity_io from so many different places.  Specifically:

- Make various functions take want_digest as a parameter rather than
  having it be implicitly passed via the struct dm_verity_io.

- Add a new tmp_digest field, and use this instead of real_digest when
  computing a digest solely for the purpose of immediately checking it.

The result is that real_digest and want_digest are used only by
verity_verify_io().

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
drivers/md/dm-verity-fec.c
drivers/md/dm-verity-fec.h
drivers/md/dm-verity-target.c
drivers/md/dm-verity.h

index d382a390d39ab8e827bae086a46a5e278cbc70ec..301a9c01bf865b02a0f64840fc2cf7594b031a46 100644 (file)
@@ -188,14 +188,13 @@ error:
  * Locate data block erasures using verity hashes.
  */
 static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
-                         u8 *want_digest, u8 *data)
+                         const u8 *want_digest, const u8 *data)
 {
        if (unlikely(verity_hash(v, io, data, 1 << v->data_dev_block_bits,
-                                verity_io_real_digest(v, io))))
+                                io->tmp_digest)))
                return 0;
 
-       return memcmp(verity_io_real_digest(v, io), want_digest,
-                     v->digest_size) != 0;
+       return memcmp(io->tmp_digest, want_digest, v->digest_size) != 0;
 }
 
 /*
@@ -366,7 +365,7 @@ static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
  */
 static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
                          struct dm_verity_fec_io *fio, u64 rsb, u64 offset,
-                         bool use_erasures)
+                         const u8 *want_digest, bool use_erasures)
 {
        int r, neras = 0;
        unsigned int pos;
@@ -392,12 +391,11 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
 
        /* Always re-validate the corrected block against the expected hash */
        r = verity_hash(v, io, fio->output, 1 << v->data_dev_block_bits,
-                       verity_io_real_digest(v, io));
+                       io->tmp_digest);
        if (unlikely(r < 0))
                return r;
 
-       if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io),
-                  v->digest_size)) {
+       if (memcmp(io->tmp_digest, want_digest, v->digest_size)) {
                DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)",
                            v->data_dev->name, (unsigned long long)rsb, neras);
                return -EILSEQ;
@@ -408,7 +406,8 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
 
 /* Correct errors in a block. Copies corrected block to dest. */
 int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
-                     enum verity_block_type type, sector_t block, u8 *dest)
+                     enum verity_block_type type, const u8 *want_digest,
+                     sector_t block, u8 *dest)
 {
        int r;
        struct dm_verity_fec_io *fio = fec_io(io);
@@ -451,9 +450,9 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
         * them first. Do a second attempt with erasures if the corruption is
         * bad enough.
         */
-       r = fec_decode_rsb(v, io, fio, rsb, offset, false);
+       r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, false);
        if (r < 0) {
-               r = fec_decode_rsb(v, io, fio, rsb, offset, true);
+               r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, true);
                if (r < 0)
                        goto done;
        }
index 09123a612953871f17e71ff37204478b388c25dc..a6689cdc489dbcffcc08156bfa38fbc59597bec5 100644 (file)
@@ -68,8 +68,8 @@ struct dm_verity_fec_io {
 extern bool verity_fec_is_enabled(struct dm_verity *v);
 
 extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
-                            enum verity_block_type type, sector_t block,
-                            u8 *dest);
+                            enum verity_block_type type, const u8 *want_digest,
+                            sector_t block, u8 *dest);
 
 extern unsigned int verity_fec_status_table(struct dm_verity *v, unsigned int sz,
                                        char *result, unsigned int maxlen);
@@ -99,6 +99,7 @@ static inline bool verity_fec_is_enabled(struct dm_verity *v)
 static inline int verity_fec_decode(struct dm_verity *v,
                                    struct dm_verity_io *io,
                                    enum verity_block_type type,
+                                   const u8 *want_digest,
                                    sector_t block, u8 *dest)
 {
        return -EOPNOTSUPP;
index bba981080563171c06c9bab53681acae97c0acf1..af9f1544af3eab7a63bfc67465eb50972e1b91b8 100644 (file)
@@ -229,12 +229,12 @@ out:
  * Verify hash of a metadata block pertaining to the specified data block
  * ("block" argument) at a specified level ("level" argument).
  *
- * On successful return, verity_io_want_digest(v, io) contains the hash value
- * for a lower tree level or for the data block (if we're at the lowest level).
+ * On successful return, want_digest contains the hash value for a lower tree
+ * level or for the data block (if we're at the lowest level).
  *
  * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
  * If "skip_unverified" is false, unverified buffer is hashed and verified
- * against current value of verity_io_want_digest(v, io).
+ * against current value of want_digest.
  */
 static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
                               sector_t block, int level, bool skip_unverified,
@@ -273,7 +273,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
                if (IS_ERR(data))
                        return r;
                if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA,
-                                     hash_block, data) == 0) {
+                                     want_digest, hash_block, data) == 0) {
                        aux = dm_bufio_get_aux_data(buf);
                        aux->hash_verified = 1;
                        goto release_ok;
@@ -293,11 +293,11 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
                }
 
                r = verity_hash(v, io, data, 1 << v->hash_dev_block_bits,
-                               verity_io_real_digest(v, io));
+                               io->tmp_digest);
                if (unlikely(r < 0))
                        goto release_ret_r;
 
-               if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
+               if (likely(memcmp(io->tmp_digest, want_digest,
                                  v->digest_size) == 0))
                        aux->hash_verified = 1;
                else if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
@@ -308,7 +308,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
                        r = -EAGAIN;
                        goto release_ret_r;
                } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA,
-                                            hash_block, data) == 0)
+                                            want_digest, hash_block, data) == 0)
                        aux->hash_verified = 1;
                else if (verity_handle_err(v,
                                           DM_VERITY_BLOCK_TYPE_METADATA,
@@ -372,7 +372,8 @@ out:
 }
 
 static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
-                                  sector_t cur_block, u8 *dest)
+                                  const u8 *want_digest, sector_t cur_block,
+                                  u8 *dest)
 {
        struct page *page;
        void *buffer;
@@ -396,12 +397,11 @@ static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
                goto free_ret;
 
        r = verity_hash(v, io, buffer, 1 << v->data_dev_block_bits,
-                       verity_io_real_digest(v, io));
+                       io->tmp_digest);
        if (unlikely(r))
                goto free_ret;
 
-       if (memcmp(verity_io_real_digest(v, io),
-                  verity_io_want_digest(v, io), v->digest_size)) {
+       if (memcmp(io->tmp_digest, want_digest, v->digest_size)) {
                r = -EIO;
                goto free_ret;
        }
@@ -416,8 +416,9 @@ free_ret:
 
 static int verity_handle_data_hash_mismatch(struct dm_verity *v,
                                            struct dm_verity_io *io,
-                                           struct bio *bio, sector_t blkno,
-                                           u8 *data)
+                                           struct bio *bio,
+                                           const u8 *want_digest,
+                                           sector_t blkno, u8 *data)
 {
        if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
                /*
@@ -426,14 +427,14 @@ static int verity_handle_data_hash_mismatch(struct dm_verity *v,
                 */
                return -EAGAIN;
        }
-       if (verity_recheck(v, io, blkno, data) == 0) {
+       if (verity_recheck(v, io, want_digest, blkno, data) == 0) {
                if (v->validated_blocks)
                        set_bit(blkno, v->validated_blocks);
                return 0;
        }
 #if defined(CONFIG_DM_VERITY_FEC)
-       if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, blkno,
-                             data) == 0)
+       if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, want_digest,
+                             blkno, data) == 0)
                return 0;
 #endif
        if (bio->bi_status)
@@ -525,8 +526,9 @@ static int verity_verify_io(struct dm_verity_io *io)
                        kunmap_local(data);
                        continue;
                }
-               r = verity_handle_data_hash_mismatch(v, io, bio, cur_block,
-                                                    data);
+               r = verity_handle_data_hash_mismatch(v, io, bio,
+                                                    verity_io_want_digest(v, io),
+                                                    cur_block, data);
                kunmap_local(data);
                if (unlikely(r))
                        return r;
index cdcee68a4bc0a5a23fddae3658bc500a9ae00680..cf7973ed30596cc1ca45e4e2a8bce08f22a5a54c 100644 (file)
@@ -99,6 +99,7 @@ struct dm_verity_io {
        struct work_struct work;
        struct work_struct bh_work;
 
+       u8 tmp_digest[HASH_MAX_DIGESTSIZE];
        u8 real_digest[HASH_MAX_DIGESTSIZE];
        u8 want_digest[HASH_MAX_DIGESTSIZE];