Skip to content

Commit 204e3e5

Browse files
committed
RDMA/odp: Check for overflow when computing the umem_odp end
Since the page size can be extended in the ODP case by IB_ACCESS_HUGETLB the existing overflow checks done by ib_umem_get() are not sufficient. Check for overflow again. Further, remove the unchecked math from the inlines and just use the precomputed value stored in the interval_tree_node. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 0446cad commit 204e3e5

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

drivers/infiniband/core/umem_odp.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,19 +287,32 @@ static inline int ib_init_umem_odp(struct ib_umem_odp *umem_odp,
287287

288288
umem_odp->umem.is_odp = 1;
289289
if (!umem_odp->is_implicit_odp) {
290-
size_t pages = ib_umem_odp_num_pages(umem_odp);
291-
290+
size_t page_size = 1UL << umem_odp->page_shift;
291+
size_t pages;
292+
293+
umem_odp->interval_tree.start =
294+
ALIGN_DOWN(umem_odp->umem.address, page_size);
295+
if (check_add_overflow(umem_odp->umem.address,
296+
umem_odp->umem.length,
297+
&umem_odp->interval_tree.last))
298+
return -EOVERFLOW;
299+
umem_odp->interval_tree.last =
300+
ALIGN(umem_odp->interval_tree.last, page_size);
301+
if (unlikely(umem_odp->interval_tree.last < page_size))
302+
return -EOVERFLOW;
303+
304+
pages = (umem_odp->interval_tree.last -
305+
umem_odp->interval_tree.start) >>
306+
umem_odp->page_shift;
292307
if (!pages)
293308
return -EINVAL;
294309

295310
/*
296311
* Note that the representation of the intervals in the
297312
* interval tree considers the ending point as contained in
298-
* the interval, while the function ib_umem_end returns the
299-
* first address which is not contained in the umem.
313+
* the interval.
300314
*/
301-
umem_odp->interval_tree.start = ib_umem_start(umem_odp);
302-
umem_odp->interval_tree.last = ib_umem_end(umem_odp) - 1;
315+
umem_odp->interval_tree.last--;
303316

304317
umem_odp->page_list = vzalloc(
305318
array_size(sizeof(*umem_odp->page_list), pages));

include/rdma/ib_umem_odp.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,13 @@ static inline struct ib_umem_odp *to_ib_umem_odp(struct ib_umem *umem)
9191
/* Returns the first page of an ODP umem. */
9292
static inline unsigned long ib_umem_start(struct ib_umem_odp *umem_odp)
9393
{
94-
return ALIGN_DOWN(umem_odp->umem.address, 1UL << umem_odp->page_shift);
94+
return umem_odp->interval_tree.start;
9595
}
9696

9797
/* Returns the address of the page after the last one of an ODP umem. */
9898
static inline unsigned long ib_umem_end(struct ib_umem_odp *umem_odp)
9999
{
100-
return ALIGN(umem_odp->umem.address + umem_odp->umem.length,
101-
1UL << umem_odp->page_shift);
100+
return umem_odp->interval_tree.last + 1;
102101
}
103102

104103
static inline size_t ib_umem_odp_num_pages(struct ib_umem_odp *umem_odp)

0 commit comments

Comments
 (0)