While freshness is outside dm-integrity's threat model, this hardens
allow_discards_keyed further against rollback of the backing device.
The keyed marker covers only the sector number, so when a block's tag
matches its marker, a read returns whatever data the backing device
holds for that block. Return zeros for such a block instead, so that a
marker restored by a rollback can at most make the block read as
discarded again.

This only adds slight overhead on the recheck path, which a read takes
only after a tag mismatch, so reads of written blocks do not reach it.

Co-developed-by: Jo Van Bulck <[email protected]>
Signed-off-by: Jo Van Bulck <[email protected]>
Signed-off-by: Shukai Ni <[email protected]>
---
 Documentation/admin-guide/device-mapper/dm-integrity.rst | 2 +-
 drivers/md/dm-integrity.c                                | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/Documentation/admin-guide/device-mapper/dm-integrity.rst 
b/Documentation/admin-guide/device-mapper/dm-integrity.rst
index 9c21301423..b60b83b22a 100644
--- a/Documentation/admin-guide/device-mapper/dm-integrity.rst
+++ b/Documentation/admin-guide/device-mapper/dm-integrity.rst
@@ -198,7 +198,7 @@ allow_discards_keyed
        Like allow_discards, but marks a discarded block with a keyed
        checksum of the sector number, HMAC_key(salt || sector), instead of
        the constant filler tag, so it can't be forged without the
-       integrity key.
+       integrity key. Reads of a discarded block return zeros.
 
        Not compatible with volumes that already have discarded blocks
        marked the old way; only use on a freshly formatted volume.
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 92970e1226..7ba8edc5aa 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -1839,7 +1839,7 @@ static void *integrity_identity(struct dm_integrity_c 
*ic, void *data)
 }
 
 static int integrity_recheck_verify_tag(struct dm_integrity_io *dio, char 
*checksum,
-                                       char *on_disk_tag, sector_t 
logical_sector)
+                                       char *on_disk_tag, sector_t 
logical_sector, char *data)
 {
        struct dm_integrity_c *ic = dio->ic;
        int r;
@@ -1857,6 +1857,8 @@ static int integrity_recheck_verify_tag(struct 
dm_integrity_io *dio, char *check
        if (unlikely(r)) {
                integrity_discard_checksum(ic, &dio->ahash_req, logical_sector, 
checksum);
                r = crypto_memneq(on_disk_tag, checksum, ic->tag_size);
+               if (!r)
+                       memset(data, 0, ic->sectors_per_block << SECTOR_SHIFT);
        }
        return r;
 }
@@ -1915,7 +1917,7 @@ static noinline void integrity_recheck(struct 
dm_integrity_io *dio, char *checks
 
                        integrity_sector_checksum(ic, &dio->ahash_req, 
logical_sector, integrity_identity(ic, buffer), buffer_offset, checksum);
                        r = integrity_recheck_verify_tag(dio, checksum, 
on_disk_tag,
-                                                        logical_sector);
+                                                        logical_sector, buffer 
+ buffer_offset);
                        if (r) {
                                if (r > 0) {
                                        DMERR_LIMIT("%pg: Checksum failed at 
sector 0x%llx",
-- 
2.53.0


Reply via email to