summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@mit.edu>2010-01-27 22:40:33 +0000
committerAlbert Astals Cid <aacid@kde.org>2010-01-27 22:41:57 +0000
commit8284008aa8230a92ba08d547864353d3290e9bf9 (patch)
tree9b5a7e75bc053bbbb1884413a82479f9a3397980
parent4ae84c830f842d100cbb702b32970951a5a5769f (diff)
Add a stack of stateGuards to Gfx
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.
-rw-r--r--poppler/Gfx.cc30
-rw-r--r--poppler/Gfx.h11
2 files changed, 40 insertions, 1 deletions
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index a9429b87..a3ed7230 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -30,7 +30,7 @@
// Copyright (C) 2009 M Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2009 William Bader <williambader@hotmail.com>
-// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -543,6 +543,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;
@@ -596,6 +597,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;
@@ -620,7 +622,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) {
@@ -668,6 +675,7 @@ void Gfx::go(GBool topLevel) {
int lastAbortCheck;
// scan a sequence of objects
+ pushStateGuard();
updateLevel = lastAbortCheck = 0;
numArgs = 0;
parser->getObj(&obj);
@@ -766,6 +774,8 @@ void Gfx::go(GBool topLevel) {
args[i].free();
}
+ popStateGuard();
+
// update display
if (topLevel && updateLevel > 0) {
out->dump();
@@ -4746,6 +4756,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();
@@ -4753,6 +4777,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 2a808ce4..fb4e3644 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -19,6 +19,7 @@
// Copyright (C) 2008, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2010 David Benjamin <davidben@mit.edu>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -34,6 +35,7 @@
#include "goo/gtypes.h"
#include "goo/GooList.h"
+#include "goo/GooVector.h"
#include "GfxState.h"
#include "Object.h"
#include "PopplerCache.h"
@@ -163,9 +165,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; }
@@ -194,6 +202,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
@@ -221,6 +230,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);