Skip to content

Commit

Permalink
lib/generic-radix-tree.c: Don't overflow in peek()
Browse files Browse the repository at this point in the history
[ Upstream commit 9492261 ]

When we started spreading new inode numbers throughout most of the 64
bit inode space, that triggered some corner case bugs, in particular
some integer overflows related to the radix tree code. Oops.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
koverstreet authored and gregkh committed Nov 28, 2023
1 parent c56df79 commit 784d01f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
7 changes: 7 additions & 0 deletions include/linux/generic-radix-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

#include <asm/page.h>
#include <linux/bug.h>
#include <linux/limits.h>
#include <linux/log2.h>
#include <linux/math.h>
#include <linux/types.h>
Expand Down Expand Up @@ -184,6 +185,12 @@ 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)
{
if (iter->offset + obj_size < iter->offset) {
iter->offset = SIZE_MAX;
iter->pos = SIZE_MAX;
return;
}

iter->offset += obj_size;

if (!is_power_of_2(obj_size) &&
Expand Down
17 changes: 14 additions & 3 deletions lib/generic-radix-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,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)
Expand All @@ -184,10 +188,17 @@ void *__genradix_iter_peek(struct genradix_iter *iter,
(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)
Expand Down

0 comments on commit 784d01f

Please sign in to comment.