kunit: Fix possible memory leak in kunit_filter_suites()
authorJinjie Ruan <ruanjinjie@huawei.com>
Wed, 27 Sep 2023 09:03:49 +0000 (17:03 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:59:15 +0000 (11:59 +0100)
[ Upstream commit 24de14c98b37ea40a7e493dfd0d93b400b6efbca ]

If the outer layer for loop is iterated more than once and it fails not
in the first iteration, the filtered_suite and filtered_suite->test_cases
allocated in the last kunit_filter_attr_tests() in last inner for loop
is leaked.

So add a new free_filtered_suite err label and free the filtered_suite
and filtered_suite->test_cases so far. And change kmalloc_array of copy
to kcalloc to Clear the copy to make the kfree safe.

Fixes: 529534e8cba3 ("kunit: Add ability to filter attributes")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Rae Moar <rmoar@google.com>
Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
lib/kunit/executor.c

index 9358ed2..1236b3c 100644 (file)
@@ -157,10 +157,11 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
        struct kunit_suite_set filtered = {NULL, NULL};
        struct kunit_glob_filter parsed_glob;
        struct kunit_attr_filter *parsed_filters = NULL;
+       struct kunit_suite * const *suites;
 
        const size_t max = suite_set->end - suite_set->start;
 
-       copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
+       copy = kcalloc(max, sizeof(*filtered.start), GFP_KERNEL);
        if (!copy) { /* won't be able to run anything, return an empty set */
                return filtered;
        }
@@ -195,7 +196,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
                                        parsed_glob.test_glob);
                        if (IS_ERR(filtered_suite)) {
                                *err = PTR_ERR(filtered_suite);
-                               goto free_parsed_filters;
+                               goto free_filtered_suite;
                        }
                }
                if (filter_count > 0 && parsed_filters != NULL) {
@@ -212,11 +213,11 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
                                filtered_suite = new_filtered_suite;
 
                                if (*err)
-                                       goto free_parsed_filters;
+                                       goto free_filtered_suite;
 
                                if (IS_ERR(filtered_suite)) {
                                        *err = PTR_ERR(filtered_suite);
-                                       goto free_parsed_filters;
+                                       goto free_filtered_suite;
                                }
                                if (!filtered_suite)
                                        break;
@@ -231,6 +232,14 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
        filtered.start = copy_start;
        filtered.end = copy;
 
+free_filtered_suite:
+       if (*err) {
+               for (suites = copy_start; suites < copy; suites++) {
+                       kfree((*suites)->test_cases);
+                       kfree(*suites);
+               }
+       }
+
 free_parsed_filters:
        if (filter_count)
                kfree(parsed_filters);