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
