[poppler] [PATCH 4/5] Add a stack of stateGuards to Gfx

David Benjamin davidben at MIT.EDU
Thu Jan 21 21:27:02 PST 2010


While a stack of states is a good way to maintain graphics contexts, if
the command stream you are interpreting is untrusted, we must place
appropriate guards to be sure that, not only do we not pop past the end
of the stack, but we do not pop past the stack as it was when we began
rendering.

This actually fixes stack check in #24575.
---
 poppler/Gfx.cc |   28 ++++++++++++++++++++++++++++
 poppler/Gfx.h  |   10 ++++++++++
 2 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index c7a3ef7..5aba7e9 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -526,6 +526,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata
   out = outA;
   state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
   stackHeight = 1;
+  pushStateGuard();
   fontChanged = gFalse;
   clip = clipNone;
   ignoreUndef = 0;
@@ -579,6 +580,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
   out = outA;
   state = new GfxState(72, 72, box, 0, gFalse);
   stackHeight = 1;
+  pushStateGuard();
   fontChanged = gFalse;
   clip = clipNone;
   ignoreUndef = 0;
@@ -603,7 +605,12 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
 }
 
 Gfx::~Gfx() {
+  while (stateGuards.size()) {
+    popStateGuard();
+  }
+  // There shouldn't be more saves, but pop them if there were any
   while (state->hasSaves()) {
+    error(-1, "Found state under last state guard. Popping.");
     restoreState();
   }
   if (!subPage) {
@@ -651,6 +658,7 @@ void Gfx::go(GBool topLevel) {
   int lastAbortCheck;
 
   // scan a sequence of objects
+  pushStateGuard();
   updateLevel = lastAbortCheck = 0;
   numArgs = 0;
   parser->getObj(&obj);
@@ -749,6 +757,8 @@ void Gfx::go(GBool topLevel) {
       args[i].free();
   }
 
+  popStateGuard();
+
   // update display
   if (topLevel && updateLevel > 0) {
     out->dump();
@@ -4729,6 +4739,20 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor, double
   }
 }
 
+int Gfx::bottomGuard() {
+    return stateGuards[stateGuards.size()-1];
+}
+
+void Gfx::pushStateGuard() {
+    stateGuards.push_back(stackHeight);
+}
+
+void Gfx::popStateGuard() {
+    while (stackHeight > bottomGuard() && state->hasSaves())
+	restoreState();
+    stateGuards.pop_back();
+}
+
 void Gfx::saveState() {
   out->saveState(state);
   state = state->save();
@@ -4736,6 +4760,10 @@ void Gfx::saveState() {
 }
 
 void Gfx::restoreState() {
+  if (stackHeight <= bottomGuard() || !state->hasSaves()) {
+    error(-1, "Restoring state when no valid states to pop");
+    return;
+  }
   state = state->restore();
   out->restoreState(state);
   stackHeight--;
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 3071f6e..1417d19 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -34,6 +34,7 @@
 
 #include "goo/gtypes.h"
 #include "goo/GooList.h"
+#include "goo/GooVector.h"
 #include "GfxState.h"
 #include "Object.h"
 #include "PopplerCache.h"
@@ -161,9 +162,15 @@ public:
   // Save graphics state.
   void saveState();
 
+  // Push a new state guard
+  void pushStateGuard();
+
   // Restore graphics state.
   void restoreState();
 
+  // Pop to state guard and pop guard
+  void popStateGuard();
+
   // Get the current graphics state object.
   GfxState *getState() { return state; }
 
@@ -192,6 +199,7 @@ private:
 
   GfxState *state;		// current graphics state
   int stackHeight;		// the height of the current graphics stack
+  GooVector<int> stateGuards;   // a stack of state limits; to guard against unmatched pops
   GBool fontChanged;		// set if font or text matrix has changed
   GfxClipType clip;		// do a clip?
   int ignoreUndef;		// current BX/EX nesting level
@@ -219,6 +227,8 @@ private:
   GBool checkArg(Object *arg, TchkType type);
   int getPos();
 
+  int bottomGuard();
+
   // graphics state operators
   void opSave(Object args[], int numArgs);
   void opRestore(Object args[], int numArgs);
-- 
1.6.6.137.g8333d.dirty



More information about the poppler mailing list