]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
generix radix trees: Don't overflow in peek()
authorKent Overstreet <kent.overstreet@gmail.com>
Sat, 13 Feb 2021 01:12:43 +0000 (20:12 -0500)
committerKent Overstreet <kent.overstreet@gmail.com>
Sat, 13 Feb 2021 02:42:46 +0000 (21:42 -0500)
include/linux/generic-radix-tree.h
linux/generic-radix-tree.c

index 3a91130a4fbd54040301f7da2baf4a242b14ab67..f09689dafb008114f9199167f6d18918d0129a9d 100644 (file)
@@ -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) &&
index 4f43d0bb4e9a8a668ed6f718336da69db4998bee..7857017c1d48a11c6ceab7e4069af4908b46a415 100644 (file)
@@ -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)