From 26fe2bf9bc763a811d52e31903a9e9b4277b955f Mon Sep 17 00:00:00 2001 From: Michael Johnson Date: Tue, 31 Jul 2007 14:39:36 +0000 Subject: - Plug a memory leak [1] - Fix an integer overflow [2] Obtained from: Poppler SVN [1] Redhat http://rhn.redhat.com/errata/RHSA-2007-0732.html [2] Security: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-3387 Reported by: miwi via irc.freenode.org/#FreeBSD-GNOME --- graphics/poppler/Makefile | 2 +- graphics/poppler/files/patch-security | 571 ++++++++++++++++++++++++++++++++++ 2 files changed, 572 insertions(+), 1 deletion(-) create mode 100644 graphics/poppler/files/patch-security (limited to 'graphics/poppler') diff --git a/graphics/poppler/Makefile b/graphics/poppler/Makefile index 0e093273f36b..5689c27e39b2 100644 --- a/graphics/poppler/Makefile +++ b/graphics/poppler/Makefile @@ -8,7 +8,7 @@ PORTNAME= poppler PORTVERSION= 0.5.9 -PORTREVISION?= 3 +PORTREVISION?= 4 CATEGORIES= graphics print MASTER_SITES= http://poppler.freedesktop.org/ diff --git a/graphics/poppler/files/patch-security b/graphics/poppler/files/patch-security new file mode 100644 index 000000000000..faeb52e575d6 --- /dev/null +++ b/graphics/poppler/files/patch-security @@ -0,0 +1,571 @@ +--- poppler/Form.cc.orig 2007-05-21 17:21:31.000000000 -0400 ++++ poppler/Form.cc 2007-07-31 09:03:35.000000000 -0400 +@@ -120,7 +120,7 @@ + + FormWidget::~FormWidget() + { +- ++ obj.free (); + } + + int FormWidget::encodeID (unsigned pageNum, unsigned fieldNum) +@@ -149,10 +149,19 @@ + { + if (siblingsID) + gfree(siblingsID); ++ delete onStr; ++} ++ ++FormButtonType FormWidgetButton::getButtonType () const ++{ ++ return parent->getButtonType (); + } + + void FormWidgetButton::setState (GBool astate, GBool calledByParent) + { ++ //pushButtons don't have state ++ if (parent->getButtonType() == formButtonPush) ++ return; + //the state modification may be denied by the parent. e.g we don't want to let the user put all combo boxes to false + if (!calledByParent) { //avoid infinite recursion + if (!parent->setState(childNum, astate)) { +@@ -162,13 +171,12 @@ + state = astate; + //update appearance + char *offStr = "Off"; +- Object *obj1 = new Object(); +- obj1->initName(state?onStr:offStr); +- obj.getDict()->set("V", obj1); +- obj1 = new Object(); +- obj1->initName(state?onStr:offStr); ++ Object obj1; ++ obj1.initName(state?getOnStr():offStr); ++ obj.getDict()->set("V", &obj1); ++ obj1.initName(state?getOnStr():offStr); + //modify the Appearance State entry as well +- obj.getDict()->set("AS", obj1); ++ obj.getDict()->set("AS", &obj1); + + //notify the xref about the update + xref->setModifiedObject(&obj, ref); +@@ -203,7 +211,7 @@ + tmpDict2->getVal(j, &obj3); + char *key = tmpDict2->getKey(j); + if(strcmp(key, "Off")) { //if we don't have Off, we have the name of the "on" state +- onStr = strdup(key); ++ onStr = new GooString (key); + } + obj3.free(); + } +@@ -213,7 +221,7 @@ + Object obj3; + tmpDict2->lookup("Length", &obj3); + int c; +- onStr = "D"; ++ onStr = new GooString ("D"); + } + obj2.free(); + } +@@ -226,10 +234,8 @@ + } + } + +- if (dict->lookup("V", &obj1)->isName()) { +- char *s = obj1.getName(); +- if(strcmp(s, "Off")) { +- //state = gTrue; ++ if (Form::fieldLookup(dict, "V", &obj1)->isName()) { ++ if (strcmp (obj1.getName(), "Off") != 0) { + setState(gTrue); + } + } else if (obj1.isArray()) { //handle the case where we have multiple choices +@@ -261,7 +267,7 @@ + Dict *dict = obj.getDict(); + Object obj1; + +- if (dict->lookup("V", &obj1)->isString()) { ++ if (Form::fieldLookup(dict, "V", &obj1)->isString()) { + if (obj1.getString()->hasUnicodeMarker()) { + if (obj1.getString()->getLength() <= 2) { + } else { +@@ -275,6 +281,7 @@ + GooString* str1 = new GooString(tmp_str, tmp_length); + parent->setContentCopy(str1); + delete str1; ++ delete []tmp_str; + } + } + } +@@ -332,6 +339,11 @@ + return parent->isReadOnly(); + } + ++int FormWidgetText::getMaxLen () const ++{ ++ return parent->getMaxLen (); ++} ++ + void FormWidgetText::setContent(GooString* new_content) + { + if (isReadOnly()) { +@@ -350,12 +362,11 @@ + + GooString *cont = new GooString(new_content); + parent->setContentCopy(cont); +- Object *obj1 = new Object(); +- obj1->initString(cont); +- obj.getDict()->set("V", obj1); ++ Object obj1; ++ obj1.initString(cont); ++ obj.getDict()->set("V", &obj1); + //notify the xref about the update + xref->setModifiedObject(&obj, ref); +- + } + } + +@@ -406,7 +417,7 @@ + memset(tmpCurrentChoice, 0, sizeof(bool)*parent->getNumChoices()); + + //find default choice +- if (dict->lookup("V", &obj1)->isString()) { ++ if (Form::fieldLookup(dict, "V", &obj1)->isString()) { + for(int i=0; igetNumChoices(); i++) { + if (parent->getChoice(i)->cmp(obj1.getString()) == 0) { + tmpCurrentChoice[i] = true; +@@ -467,33 +478,33 @@ + + void FormWidgetChoice::_updateV () + { +- Object *obj1 = new Object(); ++ Object obj1; + //this is an editable combo-box with user-entered text + if (hasEdit() && parent->getEditChoice()) { +- obj1->initString(new GooString(parent->getEditChoice())); ++ obj1.initString(new GooString(parent->getEditChoice())); + } else { + int numSelected = parent->getNumSelected(); + if (numSelected == 0) { +- obj1->initString(new GooString("")); ++ obj1.initString(new GooString("")); + } else if (numSelected == 1) { + for(int i=0; igetNumChoices(); i++) { + if (parent->isSelected(i)) { +- obj1->initString(new GooString(parent->getExportVal(i))); ++ obj1.initString(new GooString(parent->getExportVal(i))); + break; + } + } + } else { +- obj1->initArray(xref); ++ obj1.initArray(xref); + for(int i=0; igetNumChoices(); i++) { + if (parent->isSelected(i)) { +- Object* obj2 = new Object(); +- obj2->initString(new GooString(parent->getExportVal(i))); +- obj1->arrayAdd(obj2); ++ Object obj2; ++ obj2.initString(new GooString(parent->getExportVal(i))); ++ obj1.arrayAdd(&obj2); + } + } + } + } +- obj.getDict()->set("V", obj1); ++ obj.getDict()->set("V", &obj1); + //notify the xref about the update + xref->setModifiedObject(&obj, ref); + } +@@ -667,7 +678,16 @@ + array->get(i, &obj2); + array->getNF(i, &childRef); + //field child +- if(obj2.dictLookup("FT", &obj3)->isName()) { ++ if (dict->lookup ("FT", &obj3)->isName()) { ++ // If I'm not a generic container field and my children ++ // are widgets, create widgets for them ++ Object obj4; ++ ++ if (obj2.dictLookup("Subtype",&obj4)->isName()) { ++ _createWidget(&obj2, childRef.getRef()); ++ } ++ obj4.free(); ++ } else if(obj2.dictLookup("FT", &obj3)->isName()) { + if(terminal) error(-1, "Field can't have both Widget AND Field as kids\n"); + + numChildren++; +@@ -679,7 +699,7 @@ + // 1 - we will handle 'collapsed' fields (field + annot in the same dict) + // as if the annot was in the Kids array of the field + else if (obj2.dictLookup("Subtype",&obj3)->isName()) { +- _createWidget(&obj2, childRef.getRef()); ++ _createWidget(&obj2, childRef.getRef()); + } + obj2.free(); + obj3.free(); +@@ -694,7 +714,7 @@ + obj1.free(); + + //flags +- if (dict->lookup("Ff", &obj1)->isInt()) { ++ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + int flags = obj1.getInt(); + if (flags & 0x2) { // 2 -> Required + //TODO +@@ -704,18 +724,21 @@ + } + } + obj1.free(); +- + } + +-/*FormField::FormField(FormField *dest) +-{ +- type = dest->type; +-}*/ +- + FormField::~FormField() + { +- if(children) +- gfree(children); ++ if (!terminal) { ++ if(children) { ++ for (int i=0; ilookup("Ff", &obj1)->isInt()) { ++ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + int flags = obj1.getInt(); ++ + if (flags & 0x10000) { // 17 -> push button + btype = formButtonPush; + } else if (flags & 0x8000) { // 16 -> radio button +@@ -803,18 +827,23 @@ + error(-1, "FormFieldButton:: radiosInUnison flag unimplemented, please report a bug with a testcase\n"); + } + } +- obj1.free(); + } + + void FormFieldButton::fillChildrenSiblingsID() + { +- for(int i=0; i(widgets[i]); +- btn->setNumSiblingsID(numChildren-1); +- for(int j=0, counter=0; jsetSiblingsID(counter, widgets[j]->getID()); +- counter++; ++ if (!terminal) { ++ for(int i=0; ifillChildrenSiblingsID(); ++ } ++ } else { ++ for(int i=0; i(widgets[i]); ++ btn->setNumSiblingsID(numChildren-1); ++ for(int j=0, counter=0; jsetSiblingsID(counter, widgets[j]->getID()); ++ counter++; ++ } + } + } + } +@@ -825,8 +854,10 @@ + error(-1, "FormFieldButton::setState called on a readOnly field\n"); + return gFalse; + } +- +- if(btype == formButtonRadio) { ++ ++ // A check button could behave as a radio button ++ // when it's in a set of more than 1 buttons ++ if (btype == formButtonRadio || btype == formButtonCheck) { + if (!s && noAllOff) + return gFalse; //don't allow to set all radio to off + +@@ -842,17 +873,17 @@ + if (active_child >= 0) { + FormWidgetButton* actChild = static_cast(widgets[active_child]); + if (actChild->getOnStr()) { +- Object *obj1 = new Object(); +- obj1->initName(actChild->getOnStr()); +- obj.getDict()->set("V", obj1); ++ Object obj1; ++ obj1.initName(actChild->getOnStr()); ++ obj.getDict()->set("V", &obj1); + xref->setModifiedObject(&obj, ref); + } + } + } else { + active_child = -1; +- Object *obj1 = new Object(); +- obj1->initName("Off"); +- obj.getDict()->set("V", obj1); ++ Object obj1; ++ obj1.initName("Off"); ++ obj.getDict()->set("V", &obj1); + xref->setModifiedObject(&obj, ref); + } + } +@@ -874,8 +905,9 @@ + Object obj1; + content = NULL; + multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false; ++ maxLen = 0; + +- if (dict->lookup("Ff", &obj1)->isInt()) { ++ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + int flags = obj1.getInt(); + if (flags & 0x1000) // 13 -> Multiline + multiline = true; +@@ -893,6 +925,11 @@ + richText = true; + } + obj1.free(); ++ ++ if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) { ++ maxLen = obj1.getInt(); ++ } ++ obj1.free(); + } + + GooString* FormFieldText::getContentCopy () +@@ -911,7 +948,7 @@ + + FormFieldText::~FormFieldText() + { +- ++ delete content; + } + + +@@ -930,7 +967,7 @@ + + combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false; + +- if (dict->lookup("Ff", &obj1)->isInt()) { ++ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + int flags = obj1.getInt(); + if (flags & 0x20000) // 18 -> Combo + combo = true; +@@ -954,6 +991,7 @@ + delete choices[i].optionName; + } + delete [] choices; ++ delete editedChoice; + } + + void FormFieldChoice::deselectAll () +@@ -1027,9 +1065,11 @@ + + Form::Form(XRef *xrefA, Object* acroForm) + { ++ Array *array = NULL; + Object obj1; + xref = xrefA; +- Array *array = acroForm->dictLookup("Fields",&obj1)->getArray(); ++ acroForm->dictLookup("Fields",&obj1); ++ if (obj1.isArray()) array = obj1.getArray(); + obj1.free(); + if(!array) { + error(-1, "Can't get Fields array\n"); +@@ -1037,43 +1077,64 @@ + size = 0; + numFields = 0; + rootFields = NULL; +- for(int i=0; igetLength(); i++) { +- Object oref; +- array->get(i, &obj1); +- array->getNF(i, &oref); +- if (!oref.isRef()) { +- error(-1, "Direct object in rootFields"); +- continue; +- } +- +- if (numFields >= size) { +- size += 16; +- rootFields = (FormField**)greallocn(rootFields,size,sizeof(FormField*)); +- } +- +- createFieldFromDict (&obj1, &rootFields[numFields++], xrefA, oref.getRef()); +- +- //Mark readonly field +- Object obj3; +- if (obj1.dictLookup("Ff", &obj3)->isInt()) { +- int flags = obj3.getInt(); +- if (flags & 0x1) +- rootFields[numFields-1]->setReadOnly(true); +- } +- obj3.free(); ++ if (array) { ++ for(int i=0; igetLength(); i++) { ++ Object oref; ++ array->get(i, &obj1); ++ array->getNF(i, &oref); ++ if (!oref.isRef()) { ++ error(-1, "Direct object in rootFields"); ++ continue; ++ } + +- obj1.free(); +- oref.free(); ++ if (numFields >= size) { ++ size += 16; ++ rootFields = (FormField**)greallocn(rootFields,size,sizeof(FormField*)); ++ } ++ ++ createFieldFromDict (&obj1, &rootFields[numFields++], xrefA, oref.getRef()); ++ ++ //Mark readonly field ++ Object obj3; ++ if (Form::fieldLookup(obj1.getDict (), "Ff", &obj3)->isInt()) { ++ int flags = obj3.getInt(); ++ if (flags & 0x1) ++ rootFields[numFields-1]->setReadOnly(true); ++ } ++ obj3.free(); ++ ++ obj1.free(); ++ oref.free(); ++ } + } + +- checkForNeedAppearances(acroForm); ++ checkForNeedAppearances(acroForm); + } + + Form::~Form() { + int i; + for(i = 0; i< numFields; ++i) + delete rootFields[i]; +- delete [] rootFields; ++ gfree (rootFields); ++} ++ ++// Look up an inheritable field dictionary entry. ++Object *Form::fieldLookup(Dict *field, char *key, Object *obj) { ++ Dict *dict; ++ Object parent; ++ ++ dict = field; ++ if (!dict->lookup(key, obj)->isNull()) { ++ return obj; ++ } ++ obj->free(); ++ if (dict->lookup("Parent", &parent)->isDict()) { ++ fieldLookup(parent.getDict(), key, obj); ++ } else { ++ obj->initNull(); ++ } ++ parent.free(); ++ return obj; + } + + void Form::checkForNeedAppearances (Object *acroForm) +@@ -1097,7 +1158,8 @@ + void Form::createFieldFromDict (Object* obj, FormField** ptr, XRef *xrefA, const Ref& pref) + { + Object obj2; +- if(obj->dictLookup("FT", &obj2)->isName("Btn")) { ++ ++ if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) { + (*ptr) = new FormFieldButton(xrefA, obj, pref, this); + } else if (obj2.isName("Tx")) { + (*ptr) = new FormFieldText(xrefA, obj, pref, this); +@@ -1178,5 +1240,5 @@ + + FormPageWidgets::~FormPageWidgets() + { +- // TODO free widgets ? ++ gfree (widgets); + } +--- poppler/Stream.cc.orig ++++ poppler/Stream.cc +@@ -429,6 +429,13 @@ StreamPredictor::StreamPredictor(Stream + if (rowBytes < 0) { + return; + } ++ if (width <= 0 || nComps <= 0 || nBits <= 0 || ++ nComps > gfxColorMaxComps || ++ nBits > 16 || ++ width >= INT_MAX / nComps || // check for overflow in nVals ++ nVals >= (INT_MAX - 7) / nBits) { // check for overflow in rowBytes ++ return; ++ } + predLine = (Guchar *)gmalloc(rowBytes); + memset(predLine, 0, rowBytes); + predIdx = rowBytes; +--- poppler/Form.h.orig 2007-04-14 15:16:59.000000000 -0400 ++++ poppler/Form.h 2007-07-31 09:14:06.000000000 -0400 +@@ -123,10 +123,12 @@ + FormWidgetButton(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormFieldButton *p); + ~FormWidgetButton (); + ++ FormButtonType getButtonType() const; ++ + void setState (GBool state, GBool calledByParent=gFalse); + GBool getState (); + +- char* getOnStr () { return onStr; } ++ char* getOnStr () { return onStr->getCString(); } + + void loadDefaults(); + +@@ -143,7 +145,7 @@ + unsigned* siblingsID; // IDs of dependent buttons (each button of a radio field has all the others buttons + // of the same field in this array) + int numSiblingsID; +- char *onStr; ++ GooString *onStr; + FormFieldButton *parent; + GBool state; + }; +@@ -173,6 +175,7 @@ + bool isComb () const; + bool isRichText () const; + bool isReadOnly () const; ++ int getMaxLen () const; + protected: + FormFieldText *parent; + }; +@@ -329,6 +332,8 @@ + bool noScroll () const { return doNotScroll; } + bool isComb () const { return comb; } + bool isRichText () const { return richText; } ++ ++ int getMaxLen () const { return maxLen; } + protected: + GooString* content; + bool multiline; +@@ -338,6 +343,7 @@ + bool doNotScroll; + bool comb; + bool richText; ++ int maxLen; + }; + + //------------------------------------------------------------------------ +@@ -426,6 +432,8 @@ + + ~Form(); + ++ static Object *fieldLookup(Dict *field, char *key, Object *obj); ++ + int getNumFields() const { return numFields; } + FormField* getRootField(int i) const { return rootFields[i]; } + -- cgit v1.2.3