]> git.dujemihanovic.xyz Git - linux.git/commitdiff
ida: Fix crash in ida_free when the bitmap is empty
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 21 Dec 2023 16:53:57 +0000 (16:53 +0000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Dec 2023 18:02:28 +0000 (10:02 -0800)
The IDA usually detects double-frees, but that detection failed to
consider the case when there are no nearby IDs allocated and so we have a
NULL bitmap rather than simply having a clear bit.  Add some tests to the
test-suite to be sure we don't inadvertently reintroduce this problem.
Unfortunately they're quite noisy so include a message to disregard
the warnings.

Reported-by: Zhenghan Wang <wzhmmmmm@gmail.com>
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
lib/idr.c
lib/test_ida.c

index 13f2758c2377358602a3486aa5f08763c128be7d..da36054c3ca02058dcfa3338c712ba664b79b13a 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -508,7 +508,7 @@ void ida_free(struct ida *ida, unsigned int id)
                        goto delete;
                xas_store(&xas, xa_mk_value(v));
        } else {
-               if (!test_bit(bit, bitmap->bitmap))
+               if (!bitmap || !test_bit(bit, bitmap->bitmap))
                        goto err;
                __clear_bit(bit, bitmap->bitmap);
                xas_set_mark(&xas, XA_FREE_MARK);
index b0688062596150be5e29555ee237cf9a99a1d414..55105baa19da9a3b03b143bb8609ab8cbb4373e2 100644 (file)
@@ -150,6 +150,45 @@ static void ida_check_conv(struct ida *ida)
        IDA_BUG_ON(ida, !ida_is_empty(ida));
 }
 
+/*
+ * Check various situations where we attempt to free an ID we don't own.
+ */
+static void ida_check_bad_free(struct ida *ida)
+{
+       unsigned long i;
+
+       printk("vvv Ignore \"not allocated\" warnings\n");
+       /* IDA is empty; all of these will fail */
+       ida_free(ida, 0);
+       for (i = 0; i < 31; i++)
+               ida_free(ida, 1 << i);
+
+       /* IDA contains a single value entry */
+       IDA_BUG_ON(ida, ida_alloc_min(ida, 3, GFP_KERNEL) != 3);
+       ida_free(ida, 0);
+       for (i = 0; i < 31; i++)
+               ida_free(ida, 1 << i);
+
+       /* IDA contains a single bitmap */
+       IDA_BUG_ON(ida, ida_alloc_min(ida, 1023, GFP_KERNEL) != 1023);
+       ida_free(ida, 0);
+       for (i = 0; i < 31; i++)
+               ida_free(ida, 1 << i);
+
+       /* IDA contains a tree */
+       IDA_BUG_ON(ida, ida_alloc_min(ida, (1 << 20) - 1, GFP_KERNEL) != (1 << 20) - 1);
+       ida_free(ida, 0);
+       for (i = 0; i < 31; i++)
+               ida_free(ida, 1 << i);
+       printk("^^^ \"not allocated\" warnings over\n");
+
+       ida_free(ida, 3);
+       ida_free(ida, 1023);
+       ida_free(ida, (1 << 20) - 1);
+
+       IDA_BUG_ON(ida, !ida_is_empty(ida));
+}
+
 static DEFINE_IDA(ida);
 
 static int ida_checks(void)
@@ -162,6 +201,7 @@ static int ida_checks(void)
        ida_check_leaf(&ida, 1024 * 64);
        ida_check_max(&ida);
        ida_check_conv(&ida);
+       ida_check_bad_free(&ida);
 
        printk("IDA: %u of %u tests passed\n", tests_passed, tests_run);
        return (tests_run != tests_passed) ? 0 : -EINVAL;