fe99af154b
Fix a buffer overflow due to insufficient bounds checking while processing a PDF file that provides malicious values in the /Encrypt /Length tag. http://www.idefense.com/application/poi/display?id=186&type=vulnerabilities&flashstatus=false ok robert@
277 lines
7.5 KiB
Plaintext
277 lines
7.5 KiB
Plaintext
$OpenBSD: patch-xpdf_XRef_cc,v 1.2 2005/01/19 16:23:16 naddy Exp $
|
|
--- xpdf/XRef.cc.orig Thu Jan 22 02:26:45 2004
|
|
+++ xpdf/XRef.cc Wed Jan 19 14:23:39 2005
|
|
@@ -96,7 +96,7 @@ ObjectStream::ObjectStream(XRef *xref, i
|
|
}
|
|
nObjects = obj1.getInt();
|
|
obj1.free();
|
|
- if (nObjects == 0) {
|
|
+ if (nObjects <= 0) {
|
|
goto err1;
|
|
}
|
|
|
|
@@ -106,7 +106,14 @@ ObjectStream::ObjectStream(XRef *xref, i
|
|
}
|
|
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 +137,12 @@ ObjectStream::ObjectStream(XRef *xref, i
|
|
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 +382,20 @@ GBool XRef::readXRefTable(Parser *parser
|
|
}
|
|
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*sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
|
|
+ error(-1, "Invalid 'obj' parameters'");
|
|
+ return gFalse;
|
|
+ }
|
|
+ if (newSize < 0) {
|
|
+ goto err1;
|
|
+ }
|
|
entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
|
|
for (i = size; i < newSize; ++i) {
|
|
entries[i].offset = 0xffffffff;
|
|
@@ -443,7 +466,7 @@ GBool XRef::readXRefTable(Parser *parser
|
|
|
|
// 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 +497,14 @@ GBool XRef::readXRefStream(Stream *xrefS
|
|
}
|
|
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 +524,9 @@ GBool XRef::readXRefStream(Stream *xrefS
|
|
}
|
|
w[i] = obj2.getInt();
|
|
obj2.free();
|
|
+ if (w[i] < 0 || w[i] > 4) {
|
|
+ goto err1;
|
|
+ }
|
|
}
|
|
obj.free();
|
|
|
|
@@ -513,13 +546,14 @@ GBool XRef::readXRefStream(Stream *xrefS
|
|
}
|
|
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 +585,20 @@ GBool XRef::readXRefStreamSection(Stream
|
|
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*sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
|
|
+ error(-1, "Invalid 'size' inside xref table.");
|
|
+ return gFalse;
|
|
+ }
|
|
+ if (newSize < 0) {
|
|
+ return gFalse;
|
|
+ }
|
|
entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
|
|
for (i = size; i < newSize; ++i) {
|
|
entries[i].offset = 0xffffffff;
|
|
@@ -585,24 +629,26 @@ GBool XRef::readXRefStreamSection(Stream
|
|
}
|
|
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,39 +710,49 @@ 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*sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
|
|
+ error(-1, "Invalid 'obj' parameters.");
|
|
+ return gFalse;
|
|
+ }
|
|
+ if (newSize < 0) {
|
|
+ error(-1, "Bad object number");
|
|
+ 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;
|
|
}
|
|
- size = newSize;
|
|
+ if (entries[num].type == xrefEntryFree ||
|
|
+ gen >= entries[num].gen) {
|
|
+ entries[num].offset = pos - start;
|
|
+ entries[num].gen = gen;
|
|
+ entries[num].type = xrefEntryUncompressed;
|
|
+ }
|
|
}
|
|
- if (entries[num].type == xrefEntryFree ||
|
|
- gen >= entries[num].gen) {
|
|
- entries[num].offset = pos - start;
|
|
- entries[num].gen = gen;
|
|
- entries[num].type = xrefEntryUncompressed;
|
|
- }
|
|
}
|
|
}
|
|
}
|
|
@@ -705,6 +761,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));
|
|
}
|
|
@@ -756,6 +816,9 @@ GBool XRef::checkEncrypted(GString *owne
|
|
keyLength = lengthObj.getInt() / 8;
|
|
} else {
|
|
keyLength = 5;
|
|
+ }
|
|
+ if (keyLength > 16) {
|
|
+ keyLength = 16;
|
|
}
|
|
permFlags = permissions.getInt();
|
|
if (encVersion >= 1 && encVersion <= 2 &&
|