From ca12bca2764c3b80cd4490cdd53b49804582ec4e Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sun, 21 May 2023 13:42:11 +0200 Subject: [PATCH] Sanitize the glyph bounding box - if the contours count is lower than -1, the glyph is really likely wrong so just remove it from the font; - if a contour has the repeat flag then repeats count mustn't be 0. --- src/core/fonts.js | 43 +++++++++++++++++++++++++++++------ test/pdfs/issue15813.pdf.link | 1 + test/pdfs/issue16300.pdf.link | 1 + test/test_manifest.json | 17 ++++++++++++++ 4 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 test/pdfs/issue15813.pdf.link create mode 100644 test/pdfs/issue16300.pdf.link diff --git a/src/core/fonts.js b/src/core/fonts.js index 1c5ef008b..b66c1e856 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -1859,16 +1859,41 @@ class Font { length: 0, sizeOfInstructions: 0, }; - if (sourceEnd - sourceStart <= 12) { - // glyph with data less than 12 is invalid one + if ( + sourceStart < 0 || + sourceStart >= source.length || + sourceEnd > source.length || + sourceEnd - sourceStart <= 12 + ) { + // If the offsets are wrong or the glyph is too small, remove it. return glyphProfile; } const glyf = source.subarray(sourceStart, sourceEnd); - let contoursCount = signedInt16(glyf[0], glyf[1]); + + // Sanitize the glyph bounding box. + const xMin = signedInt16(glyf[2], glyf[3]); + const yMin = signedInt16(glyf[4], glyf[5]); + const xMax = signedInt16(glyf[6], glyf[7]); + const yMax = signedInt16(glyf[8], glyf[9]); + + if (xMin > xMax) { + writeSignedInt16(glyf, 2, xMax); + writeSignedInt16(glyf, 6, xMin); + } + if (yMin > yMax) { + writeSignedInt16(glyf, 4, yMax); + writeSignedInt16(glyf, 8, yMin); + } + + const contoursCount = signedInt16(glyf[0], glyf[1]); if (contoursCount < 0) { - // OTS doesn't like contour count to be less than -1. - contoursCount = -1; - writeSignedInt16(glyf, 0, contoursCount); + if (contoursCount < -1) { + // OTS doesn't like contour count to be less than -1. + // The glyph data offsets are very likely wrong and + // having something lower than -1, very likely, implies + // to have some garbage data. + return glyphProfile; + } // complex glyph, writing as is dest.set(glyf, destStart); glyphProfile.length = glyf.length; @@ -1913,6 +1938,10 @@ class Font { coordinatesLength += xyLength; if (flag & 8) { const repeat = glyf[j++]; + if (repeat === 0) { + // The repeat count should be non-zero when the repeat flag is set. + glyf[j - 1] ^= 8; + } i += repeat; coordinatesLength += repeat * xyLength; } @@ -2763,7 +2792,7 @@ class Font { // hhea tables; yMin and descent value are always negative. const metricsOverride = { unitsPerEm: int16(tables.head.data[18], tables.head.data[19]), - yMax: int16(tables.head.data[42], tables.head.data[43]), + yMax: signedInt16(tables.head.data[42], tables.head.data[43]), yMin: signedInt16(tables.head.data[38], tables.head.data[39]), ascent: signedInt16(tables.hhea.data[4], tables.hhea.data[5]), descent: signedInt16(tables.hhea.data[6], tables.hhea.data[7]), diff --git a/test/pdfs/issue15813.pdf.link b/test/pdfs/issue15813.pdf.link new file mode 100644 index 000000000..82cd5c5a0 --- /dev/null +++ b/test/pdfs/issue15813.pdf.link @@ -0,0 +1 @@ +https://github.com/mozilla/pdf.js/files/10209039/aaa.pdf diff --git a/test/pdfs/issue16300.pdf.link b/test/pdfs/issue16300.pdf.link new file mode 100644 index 000000000..ec27b5741 --- /dev/null +++ b/test/pdfs/issue16300.pdf.link @@ -0,0 +1 @@ +https://github.com/mozilla/pdf.js/files/11242244/PDF.TEST.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index a06b447f2..f461a447a 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -7608,5 +7608,22 @@ "value": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\nabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" } } + }, + { + "id": "issue16300", + "file": "pdfs/issue16300.pdf", + "md5": "45ac5cd3a159a4e9152bc1fdb685750d", + "rounds": 1, + "link": true, + "type": "eq" + }, + { + "id": "issue15813", + "file": "pdfs/issue15813.pdf", + "md5": "af5124ee1dbc39c679a903690958c5b2", + "rounds": 1, + "link": true, + "print": true, + "type": "eq" } ]