From c480a867680f27e77bfb06efa6c9208c08681329 Mon Sep 17 00:00:00 2001
From: Nikolay Shirokovskiy <nshirokovskiy@tarantool.org>
Date: Mon, 19 Jun 2023 10:52:20 +0300
Subject: [PATCH] fiber: fix use-after-free on fiber destroy/recycle

When fiber region is freed/destroyed and ENABLE_BACKTRACE is set then
`fiber_on_gc_truncate` callback is called. At this time both `used`
argument and `fiber->gc_initial_size` are equal to 0. Thus
`fiber->first_alloc_bt` is accessed which is already freed.

With a bad luck freeing fiber region can put slab back into slab arena.
So writing after free can change memory used by another thread.

Closes #9020

NO_TEST=tested by ASAN
NO_DOC=bugfix
---
 .../gh-9020-fix-use-after-free-on-fiber-finish.md         | 3 +++
 src/lib/core/fiber.c                                      | 8 ++++----
 2 files changed, 7 insertions(+), 4 deletions(-)
 create mode 100644 changelogs/unreleased/gh-9020-fix-use-after-free-on-fiber-finish.md

diff --git a/changelogs/unreleased/gh-9020-fix-use-after-free-on-fiber-finish.md b/changelogs/unreleased/gh-9020-fix-use-after-free-on-fiber-finish.md
new file mode 100644
index 0000000000..71fc747a99
--- /dev/null
+++ b/changelogs/unreleased/gh-9020-fix-use-after-free-on-fiber-finish.md
@@ -0,0 +1,3 @@
+## bugfix/core
+
+* Fixed a use-after-free bug in fiber recycling code (gh-9020).
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index 2a4d6482cf..f56e764de6 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -931,14 +931,13 @@ fiber_recycle(struct fiber *fiber)
 	fiber->storage.lua.fid_ref = FIBER_LUA_NOREF;
 	unregister_fid(fiber);
 	fiber->fid = 0;
-	/* Set before free to disable truncation system area check. */
 	fiber->gc_initial_size = 0;
-	region_free(&fiber->gc);
 #ifdef ENABLE_BACKTRACE
 	fiber->parent_bt = NULL;
 	fiber->first_alloc_bt = NULL;
 	region_set_callbacks(&fiber->gc, NULL, NULL, NULL);
 #endif
+	region_free(&fiber->gc);
 	if (fiber_is_reusable(fiber->flags)) {
 		rlist_move_entry(&cord()->dead, fiber, link);
 	} else {
@@ -1458,8 +1457,9 @@ fiber_destroy(struct cord *cord, struct fiber *f)
 	trigger_destroy(&f->on_stop);
 	rlist_del(&f->state);
 	rlist_del(&f->link);
-	/* Set before free to disable truncation system area check. */
-	f->gc_initial_size = 0;
+#ifdef ENABLE_BACKTRACE
+	region_set_callbacks(&f->gc, NULL, NULL, NULL);
+#endif
 	region_destroy(&f->gc);
 	fiber_stack_destroy(f, &cord->slabc);
 	diag_destroy(&f->diag);
-- 
GitLab