diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2021-02-12 20:12:43 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2021-02-12 21:42:46 -0500 |
commit | c28f93bc52c5a9ffe89a43c2db562b2b371648e3 (patch) | |
tree | 5b1a7d9f67bfc4cf81f6395e17aa3b4f4c361abe | |
parent | 868abec1ab5068dcab59fb8d7ad5e11b7bba89f3 (diff) |
generix radix trees: Don't overflow in peek()
-rw-r--r-- | include/linux/generic-radix-tree.h | 8 | ||||
-rw-r--r-- | linux/generic-radix-tree.c | 17 |
2 files changed, 22 insertions, 3 deletions
diff --git a/include/linux/generic-radix-tree.h b/include/linux/generic-radix-tree.h index 3a91130a..f09689da 100644 --- a/include/linux/generic-radix-tree.h +++ b/include/linux/generic-radix-tree.h @@ -183,6 +183,14 @@ void *__genradix_iter_peek(struct genradix_iter *, struct __genradix *, size_t); static inline void __genradix_iter_advance(struct genradix_iter *iter, size_t obj_size) { + size_t new_offset = iter->offset + obj_size; + + if (new_offset < iter->offset) { + iter->offset = SIZE_MAX; + iter->pos = SIZE_MAX; + return; + } + iter->offset += obj_size; if (!is_power_of_2(obj_size) && 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) |