In idr_get_next(), if the returned id from idr_get_next_ul() is greater
than INT_MAX, the function issues a warning and returns NULL without
updating the *nextid pointer. This causes a soft lockup for any caller
iterating over an IDR (e.g. via idr_for_each_entry) because they will
receive NULL, fail to advance their index, and repeatedly query the same
state forever.
Fix this by setting *nextid to INT_MAX when the bounds check fails,
ensuring the caller's iteration will terminate.
Also update the idr_get_next() test case in the radix-tree test suite
to expect INT_MAX instead of 0 when hitting this condition.
Signed-off-by: Josh Law <objecting@objecting.org>
---
lib/idr.c | 4 +++-
tools/testing/radix-tree/idr-test.c | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/idr.c b/lib/idr.c
index f25bd2b9e9a4..07098eb4ddc3 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -268,8 +268,10 @@ void *idr_get_next(struct idr *idr, int *nextid)
unsigned long id = *nextid;
void *entry = idr_get_next_ul(idr, &id);
- if (WARN_ON_ONCE(id > INT_MAX))
+ if (WARN_ON_ONCE(id > INT_MAX)) {
+ *nextid = INT_MAX;
return NULL;
+ }
*nextid = id;
return entry;
}
diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c
index 945144e98507..bf6a0da6a50a 100644
--- a/tools/testing/radix-tree/idr-test.c
+++ b/tools/testing/radix-tree/idr-test.c
@@ -213,7 +213,7 @@ void idr_u32_test1(struct idr *idr, u32 handle)
ptr = idr_get_next(idr, &sid);
if (id > INT_MAX) {
BUG_ON(ptr != NULL);
- BUG_ON(sid != 0);
+ BUG_ON(sid != INT_MAX);
} else {
BUG_ON(ptr != DUMMY_PTR);
BUG_ON(sid != id);
--
2.34.1
On Thu, 12 Mar 2026 18:19:47 +0000 Josh Law <hlcj1234567@gmail.com> wrote: > In idr_get_next(), if the returned id from idr_get_next_ul() is greater > than INT_MAX, the function issues a warning and returns NULL without > updating the *nextid pointer. This causes a soft lockup for any caller > iterating over an IDR (e.g. via idr_for_each_entry) because they will > receive NULL, fail to advance their index, and repeatedly query the same > state forever. This assumes that the idr_get_next() caller ignores the NULL return and just keeps on looping. Isn't that a caller bug and if so, do we need to defend against it here?
12 Mar 2026 20:55:15 Andrew Morton <akpm@linux-foundation.org>: > On Thu, 12 Mar 2026 18:19:47 +0000 Josh Law <hlcj1234567@gmail.com> wrote: > >> In idr_get_next(), if the returned id from idr_get_next_ul() is greater >> than INT_MAX, the function issues a warning and returns NULL without >> updating the *nextid pointer. This causes a soft lockup for any caller >> iterating over an IDR (e.g. via idr_for_each_entry) because they will >> receive NULL, fail to advance their index, and repeatedly query the same >> state forever. > > This assumes that the idr_get_next() caller ignores the NULL return and > just keeps on looping. Isn't that a caller bug and if so, do we need > to defend against it here? The risk isn't just a single loop failure; it's that idr_get_next() breaks the 'forward-progress' guarantee of the iterator. In macros like idr_for_each_entry_continue, if idr_get_next() returns NULL without advancing the pointer, the caller is left in a permanent trap. Any attempt to resume or retry the iteration results in an infinite loop of the same warning because the index is never incremented past the problematic ID. Advancing the pointer ensures the infrastructure is robust against these 'soft lockups', even if the caller's error handling is imperfect..
12 Mar 2026 20:57:48 Josh Law <hlcj1234567@gmail.com>: > 12 Mar 2026 20:55:15 Andrew Morton <akpm@linux-foundation.org>: > >> On Thu, 12 Mar 2026 18:19:47 +0000 Josh Law <hlcj1234567@gmail.com> wrote: >> >>> In idr_get_next(), if the returned id from idr_get_next_ul() is greater >>> than INT_MAX, the function issues a warning and returns NULL without >>> updating the *nextid pointer. This causes a soft lockup for any caller >>> iterating over an IDR (e.g. via idr_for_each_entry) because they will >>> receive NULL, fail to advance their index, and repeatedly query the same >>> state forever. >> >> This assumes that the idr_get_next() caller ignores the NULL return and >> just keeps on looping. Isn't that a caller bug and if so, do we need >> to defend against it here? > > The risk isn't just a single loop failure; it's that idr_get_next() breaks the 'forward-progress' guarantee of the iterator. > In macros like idr_for_each_entry_continue, if idr_get_next() returns NULL without advancing the pointer, the caller is left in a permanent trap. Any attempt to resume or retry the iteration results in an infinite loop of the same warning because the index is never incremented past the problematic ID. > Advancing the pointer ensures the infrastructure is robust against these 'soft lockups', even if the caller's error handling is imperfect.. This most definitely needs to be merged. V/R
© 2016 - 2026 Red Hat, Inc.