]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
ida: Free allocated bitmap in error path
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 2 Apr 2020 18:26:13 +0000 (14:26 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Wed, 7 Oct 2020 13:11:33 +0000 (09:11 -0400)
If a bitmap needs to be allocated, and then by the time the thread
is scheduled to be run again all the indices which would satisfy the
allocation have been allocated then we would leak the allocation.  Almost
impossible to hit in practice, but a trivial fix.  Found by Coverity.

Fixes: f32f004cddf8 ("ida: Convert to XArray")
Reported-by: coverity-bot <keescook+coverity-bot@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
lib/idr.c
tools/testing/radix-tree/idr-test.c

index c2cf2c52bbde5c54534b2227cee2176baf78383a..4d2eef0259d2c9e5be34e77f431627934144076a 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -470,6 +470,7 @@ alloc:
        goto retry;
 nospc:
        xas_unlock_irqrestore(&xas, flags);
+       kfree(alloc);
        return -ENOSPC;
 }
 EXPORT_SYMBOL(ida_alloc_range);
index 8995092d541ec60fdeeeb4b40613356cfd83d138..3b796dd5e5772e828f43f6aee46752c8b6b2e3da 100644 (file)
@@ -523,8 +523,27 @@ static void *ida_random_fn(void *arg)
        return NULL;
 }
 
+static void *ida_leak_fn(void *arg)
+{
+       struct ida *ida = arg;
+       time_t s = time(NULL);
+       int i, ret;
+
+       rcu_register_thread();
+
+       do for (i = 0; i < 1000; i++) {
+               ret = ida_alloc_range(ida, 128, 128, GFP_KERNEL);
+               if (ret >= 0)
+                       ida_free(ida, 128);
+       } while (time(NULL) < s + 2);
+
+       rcu_unregister_thread();
+       return NULL;
+}
+
 void ida_thread_tests(void)
 {
+       DEFINE_IDA(ida);
        pthread_t threads[20];
        int i;
 
@@ -536,6 +555,16 @@ void ida_thread_tests(void)
 
        while (i--)
                pthread_join(threads[i], NULL);
+
+       for (i = 0; i < ARRAY_SIZE(threads); i++)
+               if (pthread_create(&threads[i], NULL, ida_leak_fn, &ida)) {
+                       perror("creating ida thread");
+                       exit(1);
+               }
+
+       while (i--)
+               pthread_join(threads[i], NULL);
+       assert(ida_is_empty(&ida));
 }
 
 void ida_tests(void)