[PATCH] dm-integrity: return zeros for blocks with a keyed discard marker
From: Shukai Ni
Date: Fri Nov 06 2026 - 16:37:01 EST
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 <jo.vanbulck@xxxxxxxxxxxxxx>
Signed-off-by: Jo Van Bulck <jo.vanbulck@xxxxxxxxxxxxxx>
Signed-off-by: Shukai Ni <shukai.ni@xxxxxxxxxxx>
---
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