From 4980fcb9909449f4d65886ee2c1d1080bb3d55a5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 9 Apr 2024 13:07:23 +0200 Subject: [PATCH] MDEV-33867 main.query_cache_debug fails with heap-use-after-free What's happening: 1. Query_cache::insert() locks the QC and verifies that it's enabled 2. parallel thread tries to disable it. trylock fails (QC is locked) so the status becomes DISABLE_REQUEST 3. Query_cache::insert() calls Query_cache::write_result_data() which allocates a new block and unlocks the QC. 4. Query_cache::unlock() notices there are no more QC users and a pending DISABLE_REQUEST so it disables the QC and frees all the memory, including the new block that was just allocated 5. Query_cache::write_result_data() proceeds to write into the freed block Fix: change m_cache_status under a mutex. Approved by Oleksandr Byelkin --- sql/sql_cache.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 8655a75a455..c876636d383 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2530,14 +2530,9 @@ void Query_cache::destroy() void Query_cache::disable_query_cache(THD *thd) { + lock(thd); m_cache_status= DISABLE_REQUEST; - /* - If there is no requests in progress try to free buffer. - try_lock(TRY) will exit immediately if there is lock. - unlock() should free block. - */ - if (m_requests_in_progress == 0 && !try_lock(thd, TRY)) - unlock(); + unlock(); }