summaryrefslogtreecommitdiff
path: root/graphics/poppler
diff options
context:
space:
mode:
authorMichael Johnson <ahze@FreeBSD.org>2007-07-31 14:39:36 +0000
committerMichael Johnson <ahze@FreeBSD.org>2007-07-31 14:39:36 +0000
commit26fe2bf9bc763a811d52e31903a9e9b4277b955f (patch)
tree2eceec9d44f9853d59d0a53702a021254b4eef5b /graphics/poppler
parentFix build on 64bit CPUs (diff)
- 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
Notes
Notes: svn path=/head/; revision=196831
Diffstat (limited to 'graphics/poppler')
-rw-r--r--graphics/poppler/Makefile2
-rw-r--r--graphics/poppler/files/patch-security571
2 files changed, 572 insertions, 1 deletions
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; i<parent->getNumChoices(); 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; i<parent->getNumChoices(); 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; i<parent->getNumChoices(); 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; i<numChildren; i++)
++ delete children[i];
++ gfree(children);
++ }
++ } else {
++ for (int i = 0; i < numChildren; ++i)
++ delete widgets[i];
++ gfree (widgets);
++ }
+ obj.free();
+ }
+
+@@ -789,8 +812,9 @@
+
+ Object obj1;
+ btype = formButtonCheck;
+- if (dict->lookup("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<numChildren; i++) {
+- FormWidgetButton *btn = static_cast<FormWidgetButton*>(widgets[i]);
+- btn->setNumSiblingsID(numChildren-1);
+- for(int j=0, counter=0; j<numChildren; j++) {
+- if (i == j) continue;
+- btn->setSiblingsID(counter, widgets[j]->getID());
+- counter++;
++ if (!terminal) {
++ for(int i=0; i<numChildren; i++) {
++ children[i]->fillChildrenSiblingsID();
++ }
++ } else {
++ for(int i=0; i<numChildren; i++) {
++ FormWidgetButton *btn = static_cast<FormWidgetButton*>(widgets[i]);
++ btn->setNumSiblingsID(numChildren-1);
++ for(int j=0, counter=0; j<numChildren; j++) {
++ if (i == j) continue;
++ btn->setSiblingsID(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<FormWidgetButton*>(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; i<array->getLength(); 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; i<array->getLength(); 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]; }
+