From 25a9ea784b39a717a6b0f27ab4a8c21d9b3afc82 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 05 Nov 2004 18:43:19 +0000 Subject: Fix for a number of integer overflow bugs discovered by Chris Evans. 2004-11-05 Dan Williams * xpdf/Catalog.cc, xpdf/XRef.cc: Fix for a number of integer overflow bugs discovered by Chris Evans. CAN-2004-0888, Bug #156729, Red Hat Bug #137420. --- (limited to 'pdf') diff --git a/pdf/xpdf/Catalog.cc b/pdf/xpdf/Catalog.cc index c645fd0..8762cd4 100644 --- a/pdf/xpdf/Catalog.cc +++ b/pdf/xpdf/Catalog.cc @@ -64,6 +64,15 @@ Catalog::Catalog(XRef *xrefA) { } pagesSize = numPages0 = (int)obj.getNum(); obj.free(); + // The gcc doesnt optimize this away, so this check is ok, + // even if it looks like a pagesSize != pagesSize check + if (pagesSize*sizeof(Page *)/sizeof(Page *) != pagesSize || + pagesSize*sizeof(Ref)/sizeof(Ref) != pagesSize) { + error(-1, "Invalid 'pagesSize'"); + ok = gFalse; + return; + } + pages = (Page **)gmalloc(pagesSize * sizeof(Page *)); pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref)); for (i = 0; i < pagesSize; ++i) { @@ -191,6 +200,11 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { } if (start >= pagesSize) { pagesSize += 32; + if (pagesSize*sizeof(Page *)/sizeof(Page *) != pagesSize || + pagesSize*sizeof(Ref)/sizeof(Ref) != pagesSize) { + error(-1, "Invalid 'pagesSize' parameter."); + goto err3; + } pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *)); pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref)); for (j = pagesSize - 32; j < pagesSize; ++j) { diff --git a/pdf/xpdf/XRef.cc b/pdf/xpdf/XRef.cc index e0d82d2..afb787d 100644 --- a/pdf/xpdf/XRef.cc +++ b/pdf/xpdf/XRef.cc @@ -96,7 +96,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { } nObjects = obj1.getInt(); obj1.free(); - if (nObjects == 0) { + if (nObjects <= 0) { goto err1; } @@ -106,7 +106,15 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { } first = obj1.getInt(); obj1.free(); + if (first < 0) { + goto err1; + } + if (nObjects*sizeof(int)/sizeof(int) != nObjects) { + error(-1, "Invalid 'nObjects'"); + goto err1; + } + objs = new Object[nObjects]; objNums = (int *)gmalloc(nObjects * sizeof(int)); offsets = (int *)gmalloc(nObjects * sizeof(int)); @@ -130,6 +138,12 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { offsets[i] = obj2.getInt(); obj1.free(); obj2.free(); + if (objNums[i] < 0 || offsets[i] < 0 || + (i > 0 && offsets[i] < offsets[i-1])) { + delete parser; + gfree(offsets); + goto err1; + } } while (str->getChar() != EOF) ; delete parser; @@ -369,10 +383,21 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) { } n = obj.getInt(); obj.free(); + if (first < 0 || n < 0 || first + n < 0) { + goto err1; + } if (first + n > size) { for (newSize = size ? 2 * size : 1024; - first + n > newSize; + first + n > newSize && newSize > 0; newSize <<= 1) ; + if (newSize < 0) { + goto err1; + } + if (newSize*sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) { + error(-1, "Invalid 'obj' parameters'"); + goto err1; + } + entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; @@ -443,7 +468,7 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) { // check for an 'XRefStm' key if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { - pos2 = obj2.getInt(); + pos2 = (Guint)obj2.getInt(); readXRef(&pos2); if (!ok) { goto err1; @@ -474,7 +499,14 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { } newSize = obj.getInt(); obj.free(); + if (newSize < 0) { + goto err1; + } if (newSize > size) { + if (newSize * sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) { + error(-1, "Invalid 'size' parameter."); + return gFalse; + } entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; @@ -494,6 +526,9 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { } w[i] = obj2.getInt(); obj2.free(); + if (w[i] < 0 || w[i] > 4) { + goto err1; + } } obj.free(); @@ -513,13 +548,14 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { } n = obj.getInt(); obj.free(); - if (!readXRefStreamSection(xrefStr, w, first, n)) { + if (first < 0 || n < 0 || + !readXRefStreamSection(xrefStr, w, first, n)) { idx.free(); goto err0; } } } else { - if (!readXRefStreamSection(xrefStr, w, 0, size)) { + if (!readXRefStreamSection(xrefStr, w, 0, newSize)) { idx.free(); goto err0; } @@ -551,10 +587,20 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { Guint offset; int type, gen, c, newSize, i, j; + if (first + n < 0) { + return gFalse; + } if (first + n > size) { for (newSize = size ? 2 * size : 1024; - first + n > newSize; + first + n > newSize && newSize > 0; newSize <<= 1) ; + if (newSize < 0) { + return gFalse; + } + if (newSize*sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) { + error(-1, "Invalid 'size' inside xref table."); + return gFalse; + } entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; @@ -585,24 +631,26 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { } gen = (gen << 8) + c; } - switch (type) { - case 0: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryFree; - break; - case 1: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryUncompressed; - break; - case 2: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryCompressed; - break; - default: - return gFalse; + if (entries[i].offset == 0xffffffff) { + switch (type) { + case 0: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryFree; + break; + case 1: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryUncompressed; + break; + case 2: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryCompressed; + break; + default: + return gFalse; + } } } @@ -664,38 +712,48 @@ GBool XRef::constructXRef() { // look for object } else if (isdigit(*p)) { num = atoi(p); - do { - ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { + if (num > 0) { do { ++p; - } while (*p && isspace(*p)); - if (isdigit(*p)) { - gen = atoi(p); + } while (*p && isdigit(*p)); + if (isspace(*p)) { do { ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { + } while (*p && isspace(*p)); + if (isdigit(*p)) { + gen = atoi(p); do { ++p; - } while (*p && isspace(*p)); - if (!strncmp(p, "obj", 3)) { - if (num >= size) { - newSize = (num + 1 + 255) & ~255; - entries = (XRefEntry *) - grealloc(entries, newSize * sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; + } while (*p && isdigit(*p)); + if (isspace(*p)) { + do { + ++p; + } while (*p && isspace(*p)); + if (!strncmp(p, "obj", 3)) { + if (num >= size) { + newSize = (num + 1 + 255) & ~255; + if (newSize < 0) { + error(-1, "Bad object number"); + return gFalse; + } + if (newSize*sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) { + error(-1, "Invalid 'obj' parameters."); + return gFalse; + } + entries = (XRefEntry *) + grealloc(entries, newSize * sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + if (entries[num].type == xrefEntryFree || + gen >= entries[num].gen) { + entries[num].offset = pos - start; + entries[num].gen = gen; + entries[num].type = xrefEntryUncompressed; } - size = newSize; - } - if (entries[num].type == xrefEntryFree || - gen >= entries[num].gen) { - entries[num].offset = pos - start; - entries[num].gen = gen; - entries[num].type = xrefEntryUncompressed; } } } @@ -705,6 +763,10 @@ GBool XRef::constructXRef() { } else if (!strncmp(p, "endstream", 9)) { if (streamEndsLen == streamEndsSize) { streamEndsSize += 64; + if (streamEndsSize*sizeof(int)/sizeof(int) != streamEndsSize) { + error(-1, "Invalid 'endstream' parameter."); + return gFalse; + } streamEnds = (Guint *)grealloc(streamEnds, streamEndsSize * sizeof(int)); } -- cgit v0.9.1