]> granicus.if.org Git - icinga2/commitdiff
Implement recursion limit for AST expressions which don't use a separate stack frame
authorGunnar Beutner <gunnar@beutner.name>
Wed, 23 Mar 2016 07:40:32 +0000 (08:40 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Wed, 23 Mar 2016 08:03:49 +0000 (09:03 +0100)
fixes #11106

lib/base/scriptframe.cpp
lib/base/scriptframe.hpp
lib/config/expression.cpp

index 11841a153cf6b7d827cd71d3adcddc2b592d4f1d..c9aec385c20b9a1e60bfdedec32a674132680b6a 100644 (file)
@@ -26,13 +26,13 @@ using namespace icinga;
 boost::thread_specific_ptr<std::stack<ScriptFrame *> > 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<ScriptFrame *> *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);
 }
index c80f4776e22a1e7c5dee3c5e9011f6c0f58e3e0b..edb4413a69a2cc986a249d78fe9077d059776083 100644 (file)
@@ -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:
index 76b97d19e64555f945c3a171c049fd34474638b0..c87e6d1d8434775e6fbae6d71117e4c3edc64e4b 100644 (file)
@@ -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