[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