From 6ba0c5fe01ec472a6337b0cfc795b4de2abc8eea Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Wed, 23 Mar 2016 08:40:32 +0100 Subject: [PATCH] Implement recursion limit for AST expressions which don't use a separate stack frame fixes #11106 --- lib/base/scriptframe.cpp | 23 +++++++++++++++++++---- lib/base/scriptframe.hpp | 4 ++++ lib/config/expression.cpp | 11 ++++++++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/lib/base/scriptframe.cpp b/lib/base/scriptframe.cpp index 11841a153..c9aec385c 100644 --- a/lib/base/scriptframe.cpp +++ b/lib/base/scriptframe.cpp @@ -26,13 +26,13 @@ using namespace icinga; boost::thread_specific_ptr > ScriptFrame::m_ScriptFrames; ScriptFrame::ScriptFrame(void) - : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false) + : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0) { PushFrame(this); } ScriptFrame::ScriptFrame(const Value& self) - : Locals(new Dictionary()), Self(self), Sandboxed(false) + : Locals(new Dictionary()), Self(self), Sandboxed(false), Depth(0) { PushFrame(this); } @@ -43,6 +43,19 @@ ScriptFrame::~ScriptFrame(void) ASSERT(frame == this); } +void ScriptFrame::IncreaseStackDepth(void) +{ + if (Depth + 1 > 300) + BOOST_THROW_EXCEPTION(ScriptError("Stack overflow while evaluating expression: Recursion level too deep.")); + + Depth++; +} + +void ScriptFrame::DecreaseStackDepth(void) +{ + Depth--; +} + ScriptFrame *ScriptFrame::GetCurrentFrame(void) { std::stack *frames = m_ScriptFrames.get(); @@ -72,8 +85,10 @@ void ScriptFrame::PushFrame(ScriptFrame *frame) m_ScriptFrames.reset(frames); } - if (frames->size() > 500) - BOOST_THROW_EXCEPTION(ScriptError("Recursion level too deep.")); + if (!frames->empty()) { + ScriptFrame *parent = frames->top(); + frame->Depth += parent->Depth; + } frames->push(frame); } diff --git a/lib/base/scriptframe.hpp b/lib/base/scriptframe.hpp index c80f4776e..edb4413a6 100644 --- a/lib/base/scriptframe.hpp +++ b/lib/base/scriptframe.hpp @@ -33,11 +33,15 @@ struct I2_BASE_API ScriptFrame Dictionary::Ptr Locals; Value Self; bool Sandboxed; + int Depth; ScriptFrame(void); ScriptFrame(const Value& self); ~ScriptFrame(void); + void IncreaseStackDepth(void); + void DecreaseStackDepth(void); + static ScriptFrame *GetCurrentFrame(void); private: diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 76b97d19e..c87e6d1d8 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -61,14 +61,23 @@ ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) cons << "Executing:\n" << msgbuf.str();*/ #endif /* I2_DEBUG */ - return DoEvaluate(frame, dhint); + frame.IncreaseStackDepth(); + ExpressionResult result = DoEvaluate(frame, dhint); + frame.DecreaseStackDepth(); + return result; } catch (ScriptError& ex) { + frame.DecreaseStackDepth(); + ScriptBreakpoint(frame, &ex, GetDebugInfo()); throw; } catch (const std::exception& ex) { + frame.DecreaseStackDepth(); + BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo()) << boost::errinfo_nested_exception(boost::current_exception())); } + + frame.DecreaseStackDepth(); } bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const