From: Nickolai Zeldovich <nickolai@csail.mit.edu>
To: Matthew Wilcox <willy@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>,
linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org,
Nickolai Zeldovich <nickolai@csail.mit.edu>
Subject: [PATCH v1 2/3] ida: free the bitmaps that ida_alloc_range() fails to store
Date: Mon, 12 Oct 2026 20:27:02 -0400 [thread overview]
Message-ID: <20261013002703.773923-3-nickolai@csail.mit.edu> (raw)
In-Reply-To: <20261013002703.773923-1-nickolai@csail.mit.edu>
When xas_store() in ida_alloc_range() fails with -ENOMEM, nothing has
been stored, but the function loses the bitmap it was about to store:
- A bitmap allocated with GFP_NOWAIT under the lock is neither the
preallocation "alloc" nor stored. If xas_nomem() fails as well, the
function returns -ENOMEM and leaks it. If xas_nomem() succeeds, the
retry overwrites the only pointer to it and allocates a second one,
so the call succeeds and still leaks the first bitmap.
- A preallocated bitmap whose store failed is not freed on the -ENOMEM
return, because the exit path takes "bitmap == alloc" to mean that
the preallocation was stored.
- The value-to-bitmap conversion resets word 0 when its store fails
and then loses the bitmap in the same two ways.
Each occurrence leaks a 128-byte struct ida_bitmap. It takes a
GFP_NOWAIT radix_tree_node allocation failing right after a GFP_NOWAIT
kmalloc-128 allocation succeeded, which is what memory pressure looks
like to any ida_alloc_*() caller, such as create_worker() allocating
from worker_ida, get_anon_bdev() or the misc device minors.
Hand a bitmap whose store failed to "alloc", so that the retry reuses it
and the normal exit owns it, and free "alloc" on the error return
whether or not it is the bitmap of the failed store.
This was found while formally verifying ida_alloc_range() against the
kernel binary. The tools/testing/radix-tree harness cannot fail a
GFP_KERNEL node allocation or let a GFP_NOWAIT kmalloc() succeed, so it
cannot reach these paths; a user-space copy of the function with fault
injection at its four allocation sites leaks one bitmap on each of the
three paths before this change and none after it, with the same return
values.
Fixes: f32f004cddf8 ("ida: Convert to XArray")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
---
lib/idr.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/lib/idr.c b/lib/idr.c
index f298660f5c80..86c572e60f75 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -424,6 +424,7 @@ int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max,
xas_store(&xas, bitmap);
if (xas_error(&xas)) {
bitmap->bitmap[0] = 0;
+ alloc = bitmap;
goto out;
}
}
@@ -450,8 +451,10 @@ int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max,
__set_bit(bit, bitmap->bitmap);
}
xas_store(&xas, bitmap);
- if (xas_error(&xas) && !xa_is_value(bitmap))
+ if (xas_error(&xas) && !xa_is_value(bitmap)) {
__clear_bit(bit, bitmap->bitmap);
+ alloc = bitmap;
+ }
}
out:
xas_unlock_irqrestore(&xas, flags);
@@ -460,10 +463,12 @@ int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max,
bit = min % IDA_BITMAP_BITS;
goto retry;
}
- if (bitmap != alloc)
+ if (xas_error(&xas)) {
kfree(alloc);
- if (xas_error(&xas))
return xas_error(&xas);
+ }
+ if (bitmap != alloc)
+ kfree(alloc);
return xas.xa_index * IDA_BITMAP_BITS + bit;
alloc:
xas_unlock_irqrestore(&xas, flags);
--
2.53.0
next prev parent reply other threads:[~2026-10-13 0:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 0:27 [PATCH v1 0/3] ida: fix the allocation failure paths of ida_alloc_range() Nickolai Zeldovich
2026-10-13 0:27 ` [PATCH v1 1/3] ida: clear the bit of a bitmap that ida_alloc_range() failed to store Nickolai Zeldovich
2026-10-13 0:27 ` Nickolai Zeldovich [this message]
2026-10-13 0:27 ` [PATCH v1 3/3] ida: free the preallocated node on the ida_alloc_range() failure paths Nickolai Zeldovich
2026-10-13 0:46 ` [PATCH v1 0/3] ida: fix the allocation failure paths of ida_alloc_range() Andrew Morton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261013002703.773923-3-nickolai@csail.mit.edu \
--to=nickolai@csail.mit.edu \
--cc=akpm@linux-foundation.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=stable@vger.kernel.org \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®