/v1/console: prevent concurrent use of the same session by multiple requests

If there are such requests, without this change, they would all be allowed and
processed, resulting in unsafe concurrent (write) access to these data
structures, which can ultimately crash the daemon or lead to other unintended
behavior.
This commit is contained in:
Julian Brost 2026-01-07 12:43:16 +01:00
parent c716bdd0d3
commit b671e80050
2 changed files with 22 additions and 0 deletions

View file

@ -31,6 +31,12 @@ static void ScriptFrameCleanupHandler()
std::vector<String> cleanup_keys;
for (auto& kv : l_ApiScriptFrames) {
std::unique_lock frameLock(kv.second->Mutex, std::try_to_lock);
if (!frameLock) {
// If the frame is locked, it's in use, don't expire it this time.
continue;
}
if (kv.second->Seen < Utility::GetTime() - 1800)
cleanup_keys.push_back(kv.first);
}
@ -123,6 +129,13 @@ bool ConsoleHandler::ExecuteScriptHelper(const HttpRequest& request, HttpRespons
EnsureFrameCleanupTimer();
auto lsf = GetOrCreateScriptFrame(session);
std::unique_lock frameLock(lsf->Mutex, std::try_to_lock);
if (!frameLock) {
HttpUtility::SendJsonError(response, request.Params(), 409, "Session is currently in use by another request.");
return true;
}
lsf->Seen = Utility::GetTime();
if (!lsf->Locals)
@ -197,6 +210,13 @@ bool ConsoleHandler::AutocompleteScriptHelper(const HttpRequest& request, HttpRe
EnsureFrameCleanupTimer();
auto lsf = GetOrCreateScriptFrame(session);
std::unique_lock frameLock(lsf->Mutex, std::try_to_lock);
if (!frameLock) {
HttpUtility::SendJsonError(response, request.Params(), 409, "Session is currently in use by another request.");
return true;
}
lsf->Seen = Utility::GetTime();
if (!lsf->Locals)

View file

@ -5,12 +5,14 @@
#include "remote/httphandler.hpp"
#include "base/scriptframe.hpp"
#include <mutex>
namespace icinga
{
struct ApiScriptFrame
{
std::mutex Mutex;
double Seen{0};
int NextLine{1};
std::map<String, String> Lines;