[PATCH 2/3] kunit: Add kunit_move_action_to_top_or_reset() to reorder actions

From: Arthur Grillo
Date: Wed Sep 20 2023 - 02:12:16 EST


On Kunit, if we allocate a resource A and B on this order, with its
deferred actions to free them. The resource stack would be something
like this:

+---------+
| free(B) |
+---------+
| ... |
+---------+
| free(A) |
+---------+

If the deferred action of A accesses B, this would cause a
use-after-free bug. To solve that, we need a way to change the order
of actions.

Create a function to move an action to the top of the resource stack,
as shown in the diagram below.

+---------+ +---------+
| free(B) | | free(A) |
+---------+ +---------+
| ... | -> | free(B) |
+---------+ +---------+
| free(A) | | ... |
+---------+ +---------+

Signed-off-by: Arthur Grillo <arthurgrillo@xxxxxxxxxx>
---
include/kunit/resource.h | 17 +++++++++++++++++
lib/kunit/resource.c | 19 +++++++++++++++++++
2 files changed, 36 insertions(+)

diff --git a/include/kunit/resource.h b/include/kunit/resource.h
index c7383e90f5c9..c598b23680e3 100644
--- a/include/kunit/resource.h
+++ b/include/kunit/resource.h
@@ -479,4 +479,21 @@ void kunit_remove_action(struct kunit *test,
void kunit_release_action(struct kunit *test,
kunit_action_t *action,
void *ctx);
+
+/**
+ * kunit_move_action_to_top_or_reset - Move a previously added action to the top
+ * of the order of actions calls.
+ * @test: Test case to associate the action with.
+ * @action: The function to run on test exit
+ * @ctx: Data passed into @func
+ *
+ * Reorder the action stack, by moving the desired action to the top.
+ *
+ * Returns:
+ * 0 on success, an error if the action could not be inserted on the top.
+ */
+int kunit_move_action_to_top_or_reset(struct kunit *test,
+ kunit_action_t *action,
+ void *ctx);
+
#endif /* _KUNIT_RESOURCE_H */
diff --git a/lib/kunit/resource.c b/lib/kunit/resource.c
index f0209252b179..fe40a34b62a6 100644
--- a/lib/kunit/resource.c
+++ b/lib/kunit/resource.c
@@ -176,3 +176,22 @@ void kunit_release_action(struct kunit *test,
}
}
EXPORT_SYMBOL_GPL(kunit_release_action);
+
+int kunit_move_action_to_top_or_reset(struct kunit *test,
+ kunit_action_t *action,
+ void *ctx)
+{
+ struct kunit_action_ctx match_ctx;
+ struct kunit_resource *res;
+
+ match_ctx.func = action;
+ match_ctx.ctx = ctx;
+ res = kunit_find_resource(test, __kunit_action_match, &match_ctx);
+ if (res) {
+ kunit_remove_action(test, action, ctx);
+ return kunit_add_action_or_reset(test, action, ctx);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kunit_move_action_to_top_or_reset);

--
2.41.0