[PATCH 2/2] dm-integrity: fix infinite loop on discard with large tag size

Ben Cressey <[email protected]>
Newsgroups dev.linux.lists.dm-devel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
When integrity_metadata handles a discard, it fills a buffer with
DISCARD_FILLER and writes it over the tags, max_blocks blocks at a
time. If the kmalloc fails, the buffer is the on-stack array
checksums_onstack and max_size is set to HASH_MAX_DIGESTSIZE. So if the
tag size is larger than HASH_MAX_DIGESTSIZE, max_blocks is zero, bi_size
is never decremented and the loop never terminates.

Fix this by using sizeof(checksums_onstack) as max_size. The array has
MAX_TAG_SIZE bytes since commit b93b6643e9b5 ("dm integrity: fix a
crash with unusually large tag size"), so max_blocks is at least 1.

Fixes: 84597a44a9d8 ("dm integrity: add optional discard support")
Cc: [email protected]
Reviewed-by: Jose Fernandez (Anthropic) <[email protected]>
Signed-off-by: Ben Cressey <[email protected]>
Assisted-by: Claude:unspecified
---
The natural trigger needs the kmalloc to fail, so this was tested with
the fallback forced (a test-only hunk that frees the buffer for
discards): J mode, internal_hash:sha256, tag_size 100, allow_discards,
BLKDISCARD of 16 MiB. Without the fix the discard never completes and a
dm-integrity-offload kworker spins in integrity_metadata ->
dm_integrity_rw_tag (soft lockup with preempt=none); with the fix it
completes immediately. This goes after 1/2; on its own it would let the
keyed-discard fallback overflow checksums_onstack for tag sizes below
the digest size.

For stable: 1/2 is not stable material and it changes the context line
right above this hunk, so this patch will not apply verbatim to released
trees. The backport is the same one-line change; I will send it in
reply to the failed-to-apply notice.
---
 drivers/md/dm-integrity.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 73c1db7e55d5c..48eca96ca6d8c 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -1979,7 +1979,7 @@ static void integrity_metadata(struct work_struct *w)
 
 		if (unlikely(dio->op == REQ_OP_DISCARD)) {
 			unsigned int bi_size = dio->bio_details.bi_iter.bi_size;
-			unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
+			unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : sizeof(checksums_onstack);
 			unsigned int max_blocks = (max_size - extra_space) / ic->tag_size;
 			sector_t sector = dio->range.logical_sector;
 

-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.