Thomas Bogendoerfer 49fdc0
From: Yonatan Nachum <ynachum@amazon.com>
Thomas Bogendoerfer 49fdc0
Date: Mon, 9 Jan 2023 13:37:11 +0000
Thomas Bogendoerfer 49fdc0
Subject: RDMA/core: Fix ib block iterator counter overflow
Thomas Bogendoerfer 49fdc0
Patch-mainline: v6.2-rc5
Thomas Bogendoerfer 49fdc0
Git-commit: 0afec5e9cea732cb47014655685a2a47fb180c31
Thomas Bogendoerfer 49fdc0
References: bsc#1207878
Thomas Bogendoerfer 49fdc0
Thomas Bogendoerfer 49fdc0
When registering a new DMA MR after selecting the best aligned page size
Thomas Bogendoerfer 49fdc0
for it, we iterate over the given sglist to split each entry to smaller,
Thomas Bogendoerfer 49fdc0
aligned to the selected page size, DMA blocks.
Thomas Bogendoerfer 49fdc0
Thomas Bogendoerfer 49fdc0
In given circumstances where the sg entry and page size fit certain
Thomas Bogendoerfer 49fdc0
sizes and the sg entry is not aligned to the selected page size, the
Thomas Bogendoerfer 49fdc0
total size of the aligned pages we need to cover the sg entry is >= 4GB.
Thomas Bogendoerfer 49fdc0
Under this circumstances, while iterating page aligned blocks, the
Thomas Bogendoerfer 49fdc0
counter responsible for counting how much we advanced from the start of
Thomas Bogendoerfer 49fdc0
the sg entry is overflowed because its type is u32 and we pass 4GB in
Thomas Bogendoerfer 49fdc0
size. This can lead to an infinite loop inside the iterator function
Thomas Bogendoerfer 49fdc0
because the overflow prevents the counter to be larger
Thomas Bogendoerfer 49fdc0
than the size of the sg entry.
Thomas Bogendoerfer 49fdc0
Thomas Bogendoerfer 49fdc0
Fix the presented problem by changing the advancement condition to
Thomas Bogendoerfer 49fdc0
eliminate overflow.
Thomas Bogendoerfer 49fdc0
Thomas Bogendoerfer 49fdc0
Backtrace:
Thomas Bogendoerfer 49fdc0
[  192.374329] efa_reg_user_mr_dmabuf
Thomas Bogendoerfer 49fdc0
[  192.376783] efa_register_mr
Thomas Bogendoerfer 49fdc0
[  192.382579] pgsz_bitmap 0xfffff000 rounddown 0x80000000
Thomas Bogendoerfer 49fdc0
[  192.386423] pg_sz [0x80000000] umem_length[0xc0000000]
Thomas Bogendoerfer 49fdc0
[  192.392657] start 0x0 length 0xc0000000 params.page_shift 31 params.page_num 3
Thomas Bogendoerfer 49fdc0
[  192.399559] hp_cnt[3], pages_in_hp[524288]
Thomas Bogendoerfer 49fdc0
[  192.403690] umem->sgt_append.sgt.nents[1]
Thomas Bogendoerfer 49fdc0
[  192.407905] number entries: [1], pg_bit: [31]
Thomas Bogendoerfer 49fdc0
[  192.411397] biter->__sg_nents [1] biter->__sg [0000000008b0c5d8]
Thomas Bogendoerfer 49fdc0
[  192.415601] biter->__sg_advance [665837568] sg_dma_len[3221225472]
Thomas Bogendoerfer 49fdc0
[  192.419823] biter->__sg_nents [1] biter->__sg [0000000008b0c5d8]
Thomas Bogendoerfer 49fdc0
[  192.423976] biter->__sg_advance [2813321216] sg_dma_len[3221225472]
Thomas Bogendoerfer 49fdc0
[  192.428243] biter->__sg_nents [1] biter->__sg [0000000008b0c5d8]
Thomas Bogendoerfer 49fdc0
[  192.432397] biter->__sg_advance [665837568] sg_dma_len[3221225472]
Thomas Bogendoerfer 49fdc0
Thomas Bogendoerfer 49fdc0
Fixes: a808273a495c ("RDMA/verbs: Add a DMA iterator to return aligned contiguous memory blocks")
Thomas Bogendoerfer 49fdc0
Signed-off-by: Yonatan Nachum <ynachum@amazon.com>
Thomas Bogendoerfer 49fdc0
Link: https://lore.kernel.org/r/20230109133711.13678-1-ynachum@amazon.com
Thomas Bogendoerfer 49fdc0
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Thomas Bogendoerfer 49fdc0
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Thomas Bogendoerfer 49fdc0
---
Thomas Bogendoerfer 49fdc0
 drivers/infiniband/core/verbs.c |    7 +++++--
Thomas Bogendoerfer 49fdc0
 1 file changed, 5 insertions(+), 2 deletions(-)
Thomas Bogendoerfer 49fdc0
Thomas Bogendoerfer 49fdc0
--- a/drivers/infiniband/core/verbs.c
Thomas Bogendoerfer 49fdc0
+++ b/drivers/infiniband/core/verbs.c
Thomas Bogendoerfer 49fdc0
@@ -2915,15 +2915,18 @@ EXPORT_SYMBOL(__rdma_block_iter_start);
Thomas Bogendoerfer 49fdc0
 bool __rdma_block_iter_next(struct ib_block_iter *biter)
Thomas Bogendoerfer 49fdc0
 {
Thomas Bogendoerfer 49fdc0
 	unsigned int block_offset;
Thomas Bogendoerfer 49fdc0
+	unsigned int sg_delta;
Thomas Bogendoerfer 49fdc0
 
Thomas Bogendoerfer 49fdc0
 	if (!biter->__sg_nents || !biter->__sg)
Thomas Bogendoerfer 49fdc0
 		return false;
Thomas Bogendoerfer 49fdc0
 
Thomas Bogendoerfer 49fdc0
 	biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
Thomas Bogendoerfer 49fdc0
 	block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
Thomas Bogendoerfer 49fdc0
-	biter->__sg_advance += BIT_ULL(biter->__pg_bit) - block_offset;
Thomas Bogendoerfer 49fdc0
+	sg_delta = BIT_ULL(biter->__pg_bit) - block_offset;
Thomas Bogendoerfer 49fdc0
 
Thomas Bogendoerfer 49fdc0
-	if (biter->__sg_advance >= sg_dma_len(biter->__sg)) {
Thomas Bogendoerfer 49fdc0
+	if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) {
Thomas Bogendoerfer 49fdc0
+		biter->__sg_advance += sg_delta;
Thomas Bogendoerfer 49fdc0
+	} else {
Thomas Bogendoerfer 49fdc0
 		biter->__sg_advance = 0;
Thomas Bogendoerfer 49fdc0
 		biter->__sg = sg_next(biter->__sg);
Thomas Bogendoerfer 49fdc0
 		biter->__sg_nents--;