From 360913f780b1703f985304946980b271073d166c Mon Sep 17 00:00:00 2001 From: William Calliari <42240136+w1ll-i-code@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:51:03 +0100 Subject: [PATCH] Take a mutex before accessing the l_ApiScriptFrames Take a mutex to avoid race conditions in the map that lead to segmentation faults. Move the ApiScriptFrame object back behind a shared pointer to avoid holding the mutex for too long. Fixes #10674 (cherry picked from commit 11726b741cfbb0813e13193d11b69c2228836bea) --- lib/remote/consolehandler.cpp | 52 +++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/lib/remote/consolehandler.cpp b/lib/remote/consolehandler.cpp index c48821aaeff..e432abe8cc8 100644 --- a/lib/remote/consolehandler.cpp +++ b/lib/remote/consolehandler.cpp @@ -5,24 +5,22 @@ #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "config/configcompiler.hpp" -#include "base/configtype.hpp" #include "base/configwriter.hpp" #include "base/scriptglobal.hpp" #include "base/logger.hpp" #include "base/serializer.hpp" #include "base/timer.hpp" #include "base/namespace.hpp" -#include "base/initialize.hpp" #include "base/utility.hpp" #include -#include +#include using namespace icinga; REGISTER_URLHANDLER("/v1/console", ConsoleHandler); static std::mutex l_QueryMutex; -static std::map l_ApiScriptFrames; +static std::map> l_ApiScriptFrames; static Timer::Ptr l_FrameCleanupTimer; static std::mutex l_ApiScriptMutex; @@ -33,7 +31,7 @@ static void ScriptFrameCleanupHandler() std::vector cleanup_keys; for (auto& kv : l_ApiScriptFrames) { - if (kv.second.Seen < Utility::GetTime() - 1800) + if (kv.second->Seen < Utility::GetTime() - 1800) cleanup_keys.push_back(kv.first); } @@ -53,6 +51,18 @@ static void EnsureFrameCleanupTimer() }); } +static std::shared_ptr GetOrCreateScriptFrame(const String& session) { + std::unique_lock lock(l_ApiScriptMutex); + auto& frame = l_ApiScriptFrames[session]; + + // If no session was found, create a new one + if (!frame) { + frame = std::make_shared(); + } + + return frame; +} + bool ConsoleHandler::HandleRequest( const WaitGroup::Ptr&, AsioTlsStream& stream, @@ -115,16 +125,16 @@ bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::requestSeen = Utility::GetTime(); - if (!lsf.Locals) - lsf.Locals = new Dictionary(); + if (!lsf->Locals) + lsf->Locals = new Dictionary(); - String fileName = "<" + Convert::ToString(lsf.NextLine) + ">"; - lsf.NextLine++; + String fileName = "<" + Convert::ToString(lsf->NextLine) + ">"; + lsf->NextLine++; - lsf.Lines[fileName] = command; + lsf->Lines[fileName] = command; Dictionary::Ptr resultInfo; std::unique_ptr expr; @@ -134,8 +144,8 @@ bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::requestLocals; + frame.Self = lsf->Locals; frame.Sandboxed = sandboxed; exprResult = expr->Evaluate(frame); @@ -150,7 +160,7 @@ bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::requestLines[di.Path] << "\n" << String(di.Path.GetLength() + 2, ' ') << String(di.FirstColumn, ' ') << String(di.LastColumn - di.FirstColumn + 1, '^') << "\n" << ex.what() << "\n"; @@ -190,16 +200,16 @@ bool ConsoleHandler::AutocompleteScriptHelper(boost::beast::http::requestSeen = Utility::GetTime(); - if (!lsf.Locals) - lsf.Locals = new Dictionary(); + if (!lsf->Locals) + lsf->Locals = new Dictionary(); ScriptFrame frame(true); - frame.Locals = lsf.Locals; - frame.Self = lsf.Locals; + frame.Locals = lsf->Locals; + frame.Self = lsf->Locals; frame.Sandboxed = sandboxed; Dictionary::Ptr result1 = new Dictionary({