From 8a132f584d8443d3d206929edcc992b6490c001d Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 25 Nov 2020 13:44:57 +0100 Subject: [PATCH] Check the top-level /Pages dictionary when finding the trailer in `XRef.indexObjects` (issue 12402) In addition to the existing /Root and /Pages validation, also check that the /Pages-entry actually is a dictionary and that it has a valid /Count-entry. This way we can avoid picking a trailer candidate which e.g. the `Catalog.numPages` getter will just end up rejecting, thus breaking PDF document loading completely. --- src/core/obj.js | 23 +++++++++++++++-------- test/pdfs/issue12402.pdf.link | 1 + test/test_manifest.json | 9 +++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 test/pdfs/issue12402.pdf.link diff --git a/src/core/obj.js b/src/core/obj.js index b7565b7b0ed93..66af45c9579eb 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -1836,14 +1836,13 @@ var XRef = (function XRefClosure() { } } // reading XRef streams - var i, ii; - for (i = 0, ii = xrefStms.length; i < ii; ++i) { + for (let i = 0, ii = xrefStms.length; i < ii; ++i) { this.startXRefQueue.push(xrefStms[i]); this.readXRef(/* recoveryMode */ true); } // finding main trailer let trailerDict; - for (i = 0, ii = trailers.length; i < ii; ++i) { + for (let i = 0, ii = trailers.length; i < ii; ++i) { stream.pos = trailers[i]; const parser = new Parser({ lexer: new Lexer(stream), @@ -1861,18 +1860,26 @@ var XRef = (function XRefClosure() { continue; } // Do some basic validation of the trailer/root dictionary candidate. - let rootDict; try { - rootDict = dict.get("Root"); + const rootDict = dict.get("Root"); + if (!(rootDict instanceof Dict)) { + continue; + } + const pagesDict = rootDict.get("Pages"); + if (!(pagesDict instanceof Dict)) { + continue; + } + const pagesCount = pagesDict.get("Count"); + if (!Number.isInteger(pagesCount)) { + continue; + } + // The top-level /Pages dictionary isn't obviously corrupt. } catch (ex) { if (ex instanceof MissingDataException) { throw ex; } continue; } - if (!isDict(rootDict) || !rootDict.has("Pages")) { - continue; - } // taking the first one with 'ID' if (dict.has("ID")) { return dict; diff --git a/test/pdfs/issue12402.pdf.link b/test/pdfs/issue12402.pdf.link new file mode 100644 index 0000000000000..d974b03e1b978 --- /dev/null +++ b/test/pdfs/issue12402.pdf.link @@ -0,0 +1 @@ +https://github.com/mozilla/pdf.js/files/5597129/issue12402.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 935427136dd5b..3336b8e3402fb 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -842,6 +842,15 @@ "link": false, "type": "eq" }, + { "id": "issue12402", + "file": "pdfs/issue12402.pdf", + "md5": "70031cf610e24cc7164fb6ecd6980c8e", + "rounds": 1, + "link": true, + "firstPage": 8, + "lastPage": 8, + "type": "eq" + }, { "id": "issue10004", "file": "pdfs/issue10004.pdf", "md5": "64d1853060cefe3be50e5c4617dd0505",