poppler/GfxState.cc | 26 +++++++++-- poppler/JBIG2Stream.cc | 105 +++++++++++++++++++++++++++++++++++++++------ poppler/JPXStream.cc | 97 +++++++++++++++++++++++++++++++++++------ poppler/SplashOutputDev.cc | 8 +++ poppler/Stream.cc | 100 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 304 insertions(+), 32 deletions(-)
New commits: commit 397d7b4597ad4bc8ab41fd7a99078473a3c93eb0 Merge: 6013d49... 2c0f70a... Author: Albert Astals Cid <[email protected]> Date: Wed Sep 26 15:00:04 2012 +0200 Merge remote-tracking branch 'origin/poppler-0.20' commit 2c0f70afff03798165c2b609e115dc7e9c034c57 Author: Thomas Freitag <[email protected]> Date: Wed Sep 26 14:58:05 2012 +0200 More crash fixes for broken documents diff --git a/poppler/JPXStream.cc b/poppler/JPXStream.cc index 2cf616d..f1becc9 100644 --- a/poppler/JPXStream.cc +++ b/poppler/JPXStream.cc @@ -14,6 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2008, 2012 Albert Astals Cid <[email protected]> +// Copyright (C) 2012 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -257,6 +258,10 @@ JPXStream::JPXStream(Stream *strA): bitBufLen = 0; bitBufSkip = gFalse; byteCount = 0; + + curX = curY = 0; + curComp = 0; + readBufLen = 0; } JPXStream::~JPXStream() { @@ -410,6 +415,10 @@ void JPXStream::fillReadBuf() { tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles + (curX - img.xTileOffset) / img.xTileSize; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + if (img.tiles == NULL || tileIdx >= img.nXTiles * img.nYTiles || img.tiles[tileIdx].tileComps == NULL) { + error(errSyntaxError, getPos(), "Unexpected tileIdx in fillReadBuf in JPX stream"); + return; + } tileComp = &img.tiles[tileIdx].tileComps[curComp]; #else tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; @@ -420,6 +429,10 @@ void JPXStream::fillReadBuf() { error(errSyntaxError, getPos(), "Unexpected ty in fillReadBuf in JPX stream"); return; } + if (unlikely(tx >= (tileComp->x1 - tileComp->x0))) { + error(errSyntaxError, getPos(), "Unexpected tx in fillReadBuf in JPX stream"); + return; + } pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; pixBits = tileComp->prec; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid @@ -535,7 +548,10 @@ void JPXStream::getImageParams(int *bitsPerComponent, } else { cover(4); for (i = 0; i < dataLen; ++i) { - bufStr->getChar(); + if (unlikely(bufStr->getChar() == EOF)) { + error(errSyntaxError, getPos(), "Unexpected EOF in getImageParams in JPX stream"); + break; + } } } } @@ -592,6 +608,13 @@ GBool JPXStream::readBoxes() { haveImgHdr = gFalse; + // initialize in case there is a parse error + img.xSize = img.ySize = 0; + img.xOffset = img.yOffset = 0; + img.xTileSize = img.yTileSize = 0; + img.xTileOffset = img.yTileOffset = 0; + img.nComps = 0; + // check for a naked JPEG 2000 codestream (without the JP2/JPX // wrapper) -- this appears to be a violation of the PDF spec, but // Acrobat allows it @@ -895,7 +918,7 @@ GBool JPXStream::readCodestream(Guint len) { JPXTileComp *tileComp; int segType; GBool haveSIZ, haveCOD, haveQCD, haveSOT; - Guint precinctSize, style; + Guint precinctSize, style, nDecompLevels; Guint segLen, capabilities, comp, i, j, r; //----- main header @@ -998,11 +1021,15 @@ GBool JPXStream::readCodestream(Guint len) { "JPX COD marker segment before SIZ segment"); return gFalse; } + if (img.tiles == NULL || img.nXTiles * img.nYTiles == 0 || img.tiles[0].tileComps == NULL) { + error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); + return gFalse; + } if (!readUByte(&img.tiles[0].tileComps[0].style) || !readUByte(&img.tiles[0].progOrder) || !readUWord(&img.tiles[0].nLayers) || !readUByte(&img.tiles[0].multiComp) || - !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || @@ -1010,12 +1037,13 @@ GBool JPXStream::readCodestream(Guint len) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } - if (img.tiles[0].tileComps[0].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[0].tileComps[0].codeBlockW > 8 || img.tiles[0].tileComps[0].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } + img.tiles[0].tileComps[0].nDecompLevels = nDecompLevels; img.tiles[0].tileComps[0].codeBlockW += 2; img.tiles[0].tileComps[0].codeBlockH += 2; for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { @@ -1040,9 +1068,13 @@ GBool JPXStream::readCodestream(Guint len) { img.tiles[0].tileComps[0].transform; } img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)gmallocn( + (JPXResLevel *)gmallocn_checkoverflow( (img.tiles[i].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); + if (img.tiles[i].tileComps[comp].resLevels == NULL) { + error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); + return gFalse; + } for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; } @@ -1089,7 +1121,7 @@ GBool JPXStream::readCodestream(Guint len) { (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&style) || - !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || @@ -1097,12 +1129,13 @@ GBool JPXStream::readCodestream(Guint len) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } - if (img.tiles[0].tileComps[comp].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[0].tileComps[comp].codeBlockW > 8 || img.tiles[0].tileComps[comp].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } + img.tiles[0].tileComps[comp].nDecompLevels = nDecompLevels; img.tiles[0].tileComps[comp].style = (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); img.tiles[0].tileComps[comp].codeBlockW += 2; @@ -1494,7 +1527,7 @@ GBool JPXStream::readTilePart() { GBool haveSOD; Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; GBool tilePartToEOC; - Guint precinctSize, style; + Guint precinctSize, style, nDecompLevels; Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; Guint i, j, k, cbX, cbY, r, pre, sb, cbi, cbj; int segType, level; @@ -1508,8 +1541,8 @@ GBool JPXStream::readTilePart() { return gFalse; } - if ((tilePartIdx > 0 && !img.tiles[tileIdx].init) || - tileIdx >= img.nXTiles * img.nYTiles) { + if (tileIdx >= img.nXTiles * img.nYTiles || + (tilePartIdx > 0 && !img.tiles[tileIdx].init)) { error(errSyntaxError, getPos(), "Weird tile index in JPX stream"); return gFalse; } @@ -1531,7 +1564,7 @@ GBool JPXStream::readTilePart() { !readUByte(&img.tiles[tileIdx].progOrder) || !readUWord(&img.tiles[tileIdx].nLayers) || !readUByte(&img.tiles[tileIdx].multiComp) || - !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || @@ -1539,12 +1572,13 @@ GBool JPXStream::readTilePart() { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } - if (img.tiles[tileIdx].tileComps[0].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[tileIdx].tileComps[0].codeBlockW > 8 || img.tiles[tileIdx].tileComps[0].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } + img.tiles[tileIdx].tileComps[0].nDecompLevels = nDecompLevels; img.tiles[tileIdx].tileComps[0].codeBlockW += 2; img.tiles[tileIdx].tileComps[0].codeBlockH += 2; for (comp = 0; comp < img.nComps; ++comp) { @@ -1605,7 +1639,7 @@ GBool JPXStream::readTilePart() { (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&style) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || @@ -1613,12 +1647,13 @@ GBool JPXStream::readTilePart() { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } - if (img.tiles[tileIdx].tileComps[comp].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[tileIdx].tileComps[comp].codeBlockW > 8 || img.tiles[tileIdx].tileComps[comp].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } + img.tiles[tileIdx].tileComps[comp].nDecompLevels = nDecompLevels; img.tiles[tileIdx].tileComps[comp].style = (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; @@ -2350,6 +2385,12 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->res = 0; } } + tileComp = &tile->tileComps[tile->comp]; + if (tile->res >= tileComp->nDecompLevels + 1) { + if (++tile->comp == img.nComps) { + return gTrue; + } + } } break; case 3: // precinct, component, resolution level, layer @@ -2840,7 +2881,13 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, // i-quant parameters if (qStyle == 0) { cover(100); - eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; + const Guint stepIndex = 3*r - 2 + sb; + if (unlikely(stepIndex >= tileComp->nQuantSteps)) { + error(errSyntaxError, getPos(), + "Wrong index for quantSteps in inverseTransformLevel in JPX stream"); + break; + } + eps = (tileComp->quantSteps[stepIndex] >> 3) & 0x1f; shift = guard + eps - 1; mu = 0; // make gcc happy } else { @@ -2958,6 +3005,16 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, *bufPtr = dataPtr[x]; } } + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + x = tileComp->x1 - tileComp->x0 + 5; + } else { + x = tileComp->y1 - tileComp->y0 + 5; + } + if (offset + nx2 > x || nx2 == 0) { + error(errSyntaxError, getPos(), + "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream"); + return; + } inverseTransform1D(tileComp, tileComp->buf, offset, nx2); for (x = 0, bufPtr = tileComp->buf + offset; x < nx2; ++x, ++bufPtr) { dataPtr[x] = *bufPtr; @@ -2998,6 +3055,16 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, *bufPtr = dataPtr[y * tileComp->w]; } } + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + y = tileComp->x1 - tileComp->x0 + 5; + } else { + y = tileComp->y1 - tileComp->y0 + 5; + } + if (offset + ny2 > y || ny2 == 0) { + error(errSyntaxError, getPos(), + "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream"); + return; + } inverseTransform1D(tileComp, tileComp->buf, offset, ny2); for (y = 0, bufPtr = tileComp->buf + offset; y < ny2; ++y, ++bufPtr) { dataPtr[y * tileComp->w] = *bufPtr; commit 78558d24692c68212da35a88deb68069c5a06d81 Author: Thomas Freitag <[email protected]> Date: Wed Sep 26 14:32:05 2012 +0200 Fix more crashes in broken files solves 1258.pdf.SIGSEGV.dee.288 and 1255.pdf.asan.38.285, extends 1043.pdf.asan.47.50 and 557.pdf.asan.47.894 diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index 252e88d..b21c2b0 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -2173,10 +2173,16 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, Gfx *gfx, int recursio if (!(funcA = Function::parse(&obj1))) { goto err4; } + if (funcA->getInputSize() != 1) { + error(errSyntaxWarning, -1, "Bad SeparationColorSpace function"); + goto err5; + } obj1.free(); cs = new GfxSeparationColorSpace(nameA, altA, funcA); return cs; + err5: + delete funcA; err4: delete altA; err3: @@ -3096,6 +3102,10 @@ void GfxUnivariateShading::getColor(double t, GfxColor *color) { out[i] = 0; } for (i = 0; i < nFuncs; ++i) { + if (funcs[i]->getInputSize() != 1) { + error(errSyntaxWarning, -1, "Invalid shading function (input != 1)"); + break; + } funcs[i]->transform(&t, &out[i]); } } @@ -3267,7 +3277,7 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict, Gfx *gfx) { dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { + if (nFuncsA > gfxColorMaxComps || nFuncsA == 0) { error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); goto err1; } @@ -3292,9 +3302,19 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict, Gfx *gfx) { extend0A = extend1A = gFalse; if (dict->lookup("Extend", &obj1)->isArray() && obj1.arrayGetLength() == 2) { - extend0A = obj1.arrayGet(0, &obj2)->getBool(); + obj1.arrayGet(0, &obj2); + if (obj2.isBool()) { + extend0A = obj2.getBool(); + } else { + error(errSyntaxWarning, -1, "Invalid axial shading extend (0)"); + } obj2.free(); - extend1A = obj1.arrayGet(1, &obj2)->getBool(); + obj1.arrayGet(1, &obj2); + if (obj2.isBool()) { + extend1A = obj2.getBool(); + } else { + error(errSyntaxWarning, -1, "Invalid axial shading extend (1)"); + } obj2.free(); } obj1.free(); commit e8822c0f3a46195ec7c6e55c556dd0c5716be742 Author: Albert Astals Cid <[email protected]> Date: Wed Sep 26 14:21:46 2012 +0200 Add unlikelys diff --git a/poppler/Stream.cc b/poppler/Stream.cc index b94d923..f287406 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -1757,7 +1757,7 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1766,7 +1766,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertR3: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1778,7 +1778,7 @@ int CCITTFaxStream::lookChar() { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1788,7 +1788,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertR2: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1800,7 +1800,7 @@ int CCITTFaxStream::lookChar() { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1810,7 +1810,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertR1: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1822,7 +1822,7 @@ int CCITTFaxStream::lookChar() { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1832,7 +1832,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVert0: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1844,7 +1844,7 @@ int CCITTFaxStream::lookChar() { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1854,7 +1854,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL3: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1870,7 +1870,7 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1880,7 +1880,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL2: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1896,7 +1896,7 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1906,7 +1906,7 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL1: - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -1922,7 +1922,7 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; - if (b1i > columns + 1) { + if (unlikely(b1i > columns + 1)) { error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); err = gTrue; @@ -2111,7 +2111,7 @@ int CCITTFaxStream::lookChar() { outputBits = 0; if (codingLine[a0i] < columns) { ++a0i; - if (a0i > columns) { + if (unlikely(a0i > columns)) { error(errSyntaxError, getPos(), "Bad bits {0:04x} in CCITTFax stream", bits); err = gTrue; commit 31874f2e065b0d68f726ef404de98f42489c80c7 Author: Thomas Freitag <[email protected]> Date: Wed Sep 26 14:17:00 2012 +0200 Less crashes in broken files rebased patch for 1001.pdf.asan.2a.4, extends patch for 100.pdf.asan.38.2 diff --git a/poppler/Stream.cc b/poppler/Stream.cc index 4ce6c00..b94d923 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -1707,7 +1707,7 @@ int CCITTFaxStream::lookChar() { // 2-D encoding if (nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) { + for (i = 0; i < columns && codingLine[i] < columns; ++i) { refLine[i] = codingLine[i]; } refLine[i++] = columns; @@ -1723,7 +1723,7 @@ int CCITTFaxStream::lookChar() { // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible // exception at right edge: // refLine[b1i] = refLine[b1i+1] = columns is possible - while (codingLine[a0i] < columns) { + while (codingLine[a0i] < columns && !err) { code1 = getTwoDimCode(); switch (code1) { case twoDimPass: @@ -1757,49 +1757,109 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } break; case twoDimVertR3: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i] + 3, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertR2: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i] + 2, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertR1: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i] + 1, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVert0: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i], blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertL3: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixelsNeg(refLine[b1i] - 3, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { @@ -1810,10 +1870,22 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertL2: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixelsNeg(refLine[b1i] - 2, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { @@ -1824,10 +1896,22 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertL1: + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixelsNeg(refLine[b1i] - 1, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { @@ -1838,6 +1922,12 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (b1i > columns + 1) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; @@ -2021,6 +2111,12 @@ int CCITTFaxStream::lookChar() { outputBits = 0; if (codingLine[a0i] < columns) { ++a0i; + if (a0i > columns) { + error(errSyntaxError, getPos(), + "Bad bits {0:04x} in CCITTFax stream", bits); + err = gTrue; + break; + } outputBits = codingLine[a0i] - codingLine[a0i - 1]; } else if (bits > 0) { buf <<= bits; commit 81b1d9207840ec1e66eef469b29a36a8556b7265 Author: Albert Astals Cid <[email protected]> Date: Wed Sep 26 13:38:54 2012 +0200 Add some unlikelys diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc index 5789959..afba8c6 100644 --- a/poppler/JBIG2Stream.cc +++ b/poppler/JBIG2Stream.cc @@ -586,7 +586,7 @@ int JBIG2MMRDecoder::getBlackCode() { } else { code = buf >> (bufLen - 12); } - if ((code & 0xff) < 64) { + if (unlikely((code & 0xff) < 64)) { break; } p = &blackTab2[(code & 0xff) - 64]; @@ -1105,7 +1105,7 @@ public: virtual ~JBIG2PatternDict(); virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } Guint getSize() { return size; } - void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { if (idx < size) bitmaps[idx] = bitmap; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { if (likely(idx < size)) bitmaps[idx] = bitmap; } JBIG2Bitmap *getBitmap(Guint idx) { return (idx < size) ? bitmaps[idx] : NULL; } private: @@ -1766,7 +1766,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, goto syntaxError; } symHeight += dh; - if (symHeight > 0x40000000) { + if (unlikely(symHeight > 0x40000000)) { error(errSyntaxError, curStr->getPos(), "Bad height value in JBIG2 symbol dictionary"); goto syntaxError; } @@ -1837,7 +1837,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, goto syntaxError; } refBitmap = bitmaps[symID]; - if (!refBitmap) { + if (unlikely(refBitmap == NULL)) { error(errSyntaxError, curStr->getPos(), "Invalid ref bitmap for symbol ID {0:d} in JBIG2 symbol dictionary", symID); goto syntaxError; } @@ -1876,7 +1876,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); bmSize = symHeight * ((totalWidth + 7) >> 3); p = collBitmap->getDataPtr(); - if (p == NULL) { + if (unlikely(p == NULL)) { delete collBitmap; goto syntaxError; } @@ -2229,7 +2229,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, symCodeTab[i++].prefixLen = 0; } } else if (j > 0x100) { - if (i == 0) ++i; + if (unlikely(i == 0)) ++i; for (j -= 0x100; j && i < numSyms; --j) { symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; ++i; @@ -2397,7 +2397,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, if (symID >= (Guint)numSyms) { error(errSyntaxError, curStr->getPos(), "Invalid symbol number in JBIG2 text region"); - if (numInstances - inst > 0x800) { + if (unlikely(numInstances - inst > 0x800)) { // don't loop too often with damaged JBIg2 streams delete bitmap; return NULL; @@ -2453,7 +2453,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, //~ something is wrong here - refCorner shouldn't degenerate into //~ two cases bw = symbolBitmap->getWidth() - 1; - if (symbolBitmap->getHeight() == 0) { + if (unlikely(symbolBitmap->getHeight() == 0)) { error(errSyntaxError, curStr->getPos(), "Invalid symbol bitmap height"); if (ri) { delete symbolBitmap; @@ -2463,7 +2463,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, } bh = symbolBitmap->getHeight() - 1; if (transposed) { - if (s > 2 * bitmap->getHeight()) { + if (unlikely(s > 2 * bitmap->getHeight())) { error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); if (ri) { delete symbolBitmap; @@ -2489,7 +2489,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, } else { switch (refCorner) { case 0: // bottom left - if (tt - (int) bh > 2 * bitmap->getHeight()) { + if (unlikely(tt - (int) bh > 2 * bitmap->getHeight())) { error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); if (ri) { delete symbolBitmap; @@ -2500,7 +2500,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 1: // top left - if (tt > 2 * bitmap->getHeight()) { + if (unlikely(tt > 2 * bitmap->getHeight())) { error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); if (ri) { delete symbolBitmap; @@ -2511,7 +2511,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, bitmap->combine(symbolBitmap, s, tt, combOp); break; case 2: // bottom right - if (tt - (int) bh > 2 * bitmap->getHeight()) { + if (unlikely(tt - (int) bh > 2 * bitmap->getHeight())) { error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); if (ri) { delete symbolBitmap; @@ -2522,7 +2522,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 3: // top right - if (tt > 2 * bitmap->getHeight()) { + if (unlikely(tt > 2 * bitmap->getHeight())) { error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); if (ri) { delete symbolBitmap; @@ -2756,7 +2756,7 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, for (n = 0; n < gridW; ++n) { if (!(enableSkip && skipBitmap->getPixel(n, m))) { patternBitmap = patternDict->getBitmap(grayImg[i]); - if (patternBitmap == NULL) { + if (unlikely(patternBitmap == NULL)) { error(errSyntaxError, curStr->getPos(), "Bad pattern bitmap"); return; } commit 9ae1184e3049cabc695c8645a10eaef748b6e641 Author: Thomas Freitag <[email protected]> Date: Wed Sep 26 12:32:26 2012 +0200 More fixes against broken files solves 121.pdf.asan.6f.235, extends 682.pdf.SIGFPE.f3.1033 and 569.pdf.SIGSEGV.c1.907, extends Patch for 829. and 839. asan and sigsegv series diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc index 78a205d..5789959 100644 --- a/poppler/JBIG2Stream.cc +++ b/poppler/JBIG2Stream.cc @@ -19,6 +19,7 @@ // Copyright (C) 2009 David Benjamin <[email protected]> // Copyright (C) 2011 Edward Jiang <[email protected]> // Copyright (C) 2012 William Bader <[email protected]> +// Copyright (C) 2012 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -585,6 +586,9 @@ int JBIG2MMRDecoder::getBlackCode() { } else { code = buf >> (bufLen - 12); } + if ((code & 0xff) < 64) { + break; + } p = &blackTab2[(code & 0xff) - 64]; } else { if (bufLen <= 6) { @@ -713,8 +717,10 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): return; } // need to allocate one extra guard byte for use in combine() - data = (Guchar *)gmalloc(h * line + 1); - data[h * line] = 0; + data = (Guchar *)gmalloc_checkoverflow(h * line + 1); + if (data != NULL) { + data[h * line] = 0; + } } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): @@ -1099,8 +1105,8 @@ public: virtual ~JBIG2PatternDict(); virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } Guint getSize() { return size; } - void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } - JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { if (idx < size) bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return (idx < size) ? bitmaps[idx] : NULL; } private: @@ -1111,8 +1117,13 @@ private: JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { - size = sizeA; - bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn_checkoverflow(sizeA, sizeof(JBIG2Bitmap *)); + if (bitmaps) { + size = sizeA; + } else { + size = 0; + error(errSyntaxError, -1, "JBIG2PatternDict: can't allocate bitmaps"); + } } JBIG2PatternDict::~JBIG2PatternDict() { @@ -1755,6 +1766,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, goto syntaxError; } symHeight += dh; + if (symHeight > 0x40000000) { + error(errSyntaxError, curStr->getPos(), "Bad height value in JBIG2 symbol dictionary"); + goto syntaxError; + } symWidth = 0; totalWidth = 0; j = i; @@ -1822,6 +1837,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, goto syntaxError; } refBitmap = bitmaps[symID]; + if (!refBitmap) { + error(errSyntaxError, curStr->getPos(), "Invalid ref bitmap for symbol ID {0:d} in JBIG2 symbol dictionary", symID); + goto syntaxError; + } bitmaps[numInputSyms + i] = readGenericRefinementRegion(symWidth, symHeight, sdrTemplate, gFalse, @@ -1857,6 +1876,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); bmSize = symHeight * ((totalWidth + 7) >> 3); p = collBitmap->getDataPtr(); + if (p == NULL) { + delete collBitmap; + goto syntaxError; + } for (k = 0; k < (Guint)bmSize; ++k) { if ((c = curStr->getChar()) == EOF) { break; @@ -2206,6 +2229,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, symCodeTab[i++].prefixLen = 0; } } else if (j > 0x100) { + if (i == 0) ++i; for (j -= 0x100; j && i < numSyms; --j) { symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; ++i; @@ -2373,6 +2397,11 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, if (symID >= (Guint)numSyms) { error(errSyntaxError, curStr->getPos(), "Invalid symbol number in JBIG2 text region"); + if (numInstances - inst > 0x800) { + // don't loop too often with damaged JBIg2 streams + delete bitmap; + return NULL; + } } else { // get the symbol bitmap @@ -2424,8 +2453,24 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, //~ something is wrong here - refCorner shouldn't degenerate into //~ two cases bw = symbolBitmap->getWidth() - 1; + if (symbolBitmap->getHeight() == 0) { + error(errSyntaxError, curStr->getPos(), "Invalid symbol bitmap height"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bh = symbolBitmap->getHeight() - 1; if (transposed) { + if (s > 2 * bitmap->getHeight()) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } switch (refCorner) { case 0: // bottom left bitmap->combine(symbolBitmap, tt, s, combOp); @@ -2444,15 +2489,47 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, } else { switch (refCorner) { case 0: // bottom left + if (tt - (int) bh > 2 * bitmap->getHeight()) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 1: // top left + if (tt > 2 * bitmap->getHeight()) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt, combOp); break; case 2: // bottom right + if (tt - (int) bh > 2 * bitmap->getHeight()) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 3: // top right + if (tt > 2 * bitmap->getHeight()) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt, combOp); break; } @@ -2528,7 +2605,7 @@ void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { // split up the bitmap x = 0; - for (i = 0; i <= grayMax; ++i) { + for (i = 0; i <= grayMax && i < patternDict->getSize(); ++i) { patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); x += patternW; } @@ -2679,6 +2756,10 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, for (n = 0; n < gridW; ++n) { if (!(enableSkip && skipBitmap->getPixel(n, m))) { patternBitmap = patternDict->getBitmap(grayImg[i]); + if (patternBitmap == NULL) { + error(errSyntaxError, curStr->getPos(), "Bad pattern bitmap"); + return; + } bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); } xx += stepX; @@ -3135,7 +3216,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atx[2] >= -8 && atx[2] <= 8 && atx[3] >= -8 && atx[3] <= 8) { // set up the adaptive context - if (y + aty[0] >= 0) { + if (y + aty[0] >= 0 && y + aty[0] < bitmap->getHeight()) { atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize(); atBuf0 = *atP0++ << 8; } else { @@ -3143,7 +3224,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atBuf0 = 0; } atShift0 = 15 - atx[0]; - if (y + aty[1] >= 0) { + if (y + aty[1] >= 0 && y + aty[1] < bitmap->getHeight()) { atP1 = bitmap->getDataPtr() + (y + aty[1]) * bitmap->getLineSize(); atBuf1 = *atP1++ << 8; } else { @@ -3151,7 +3232,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atBuf1 = 0; } atShift1 = 15 - atx[1]; - if (y + aty[2] >= 0) { + if (y + aty[2] >= 0 && y + aty[2] < bitmap->getHeight()) { atP2 = bitmap->getDataPtr() + (y + aty[2]) * bitmap->getLineSize(); atBuf2 = *atP2++ << 8; } else { @@ -3159,7 +3240,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atBuf2 = 0; } atShift2 = 15 - atx[2]; - if (y + aty[3] >= 0) { + if (y + aty[3] >= 0 && y + aty[3] < bitmap->getHeight()) { atP3 = bitmap->getDataPtr() + (y + aty[3]) * bitmap->getLineSize(); atBuf3 = *atP3++ << 8; } else { @@ -3678,7 +3759,7 @@ void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, refBitmap, 0, 0, atx, aty); // combine the region bitmap into the page bitmap - if (imm) { + if (imm && bitmap) { pageBitmap->combine(bitmap, x, y, extCombOp); delete bitmap; commit 1d72c14b3877ae730ac0aa92f36923269e8a2004 Author: Thomas Freitag <[email protected]> Date: Wed Sep 26 11:48:14 2012 +0200 Fix crash in 158.pdf.asan.d.451 diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 9e07060..79c4900 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -2282,6 +2282,14 @@ GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, // create new entry in the font cache if (nT3Fonts == splashOutT3FontCacheSize) { + t3gs = t3GlyphStack; + while (t3gs != NULL) { + if (t3gs->cache == t3FontCache[nT3Fonts - 1]) { + error(errSyntaxWarning, -1, "t3FontCache reaches limit but font still on stack in SplashOutputDev::beginType3Char"); + return gTrue; + } + t3gs = t3gs->next; + } delete t3FontCache[nT3Fonts - 1]; --nT3Fonts; } _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
