summaryrefslogtreecommitdiff
path: root/linux/generic-radix-tree.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-02-12 20:12:43 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2021-02-12 21:42:46 -0500
commitc28f93bc52c5a9ffe89a43c2db562b2b371648e3 (patch)
tree5b1a7d9f67bfc4cf81f6395e17aa3b4f4c361abe /linux/generic-radix-tree.c
parent868abec1ab5068dcab59fb8d7ad5e11b7bba89f3 (diff)
generix radix trees: Don't overflow in peek()
Diffstat (limited to 'linux/generic-radix-tree.c')
-rw-r--r--linux/generic-radix-tree.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/linux/generic-radix-tree.c b/linux/generic-radix-tree.c
index 4f43d0bb..7857017c 100644
--- a/linux/generic-radix-tree.c
+++ b/linux/generic-radix-tree.c
@@ -147,6 +147,10 @@ void *__genradix_iter_peek(struct genradix_iter *iter,
struct genradix_root *r;
struct genradix_node *n;
unsigned level, i;
+
+ if (iter->offset == SIZE_MAX)
+ return NULL;
+
restart:
r = READ_ONCE(radix->root);
if (!r)
@@ -165,10 +169,17 @@ restart:
(GENRADIX_ARY - 1);
while (!n->children[i]) {
+ size_t objs_per_ptr = genradix_depth_size(level);
+
+ if (iter->offset + objs_per_ptr < iter->offset) {
+ iter->offset = SIZE_MAX;
+ iter->pos = SIZE_MAX;
+ return NULL;
+ }
+
i++;
- iter->offset = round_down(iter->offset +
- genradix_depth_size(level),
- genradix_depth_size(level));
+ iter->offset = round_down(iter->offset + objs_per_ptr,
+ objs_per_ptr);
iter->pos = (iter->offset >> PAGE_SHIFT) *
objs_per_page;
if (i == GENRADIX_ARY)