From e62973d277c57d8cc0a70c27afe0eb4958b78c42 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 25 Jun 2024 15:10:09 +0100 Subject: [PATCH] In QPDF check for page tree after reading xref table Also add new fuzz test case. --- fuzz/CMakeLists.txt | 1 + fuzz/qpdf_extra/69857.fuzz | Bin 0 -> 53677 bytes fuzz/qtest/fuzz.test | 2 +- libqpdf/QPDF.cc | 4 ++++ libqpdf/QPDFWriter.cc | 1 - qpdf/qpdf.testcov | 1 - qpdf/qtest/invalid-objects.test | 2 +- qpdf/qtest/qpdf/bad11-recover.out | 1 + qpdf/qtest/qpdf/bad12-recover.out | 1 + qpdf/qtest/qpdf/bad12.out | 1 + qpdf/qtest/qpdf/bad2-recover.out | 1 + qpdf/qtest/qpdf/bad3-recover.out | 1 + qpdf/qtest/qpdf/bad4-recover.out | 1 + qpdf/qtest/qpdf/bad5-recover.out | 1 + qpdf/qtest/qpdf/bad6-recover.out | 1 + qpdf/qtest/qpdf/bad6.out | 1 + qpdf/qtest/qpdf/bad8-recover.out | 1 + qpdf/qtest/qpdf/fuzz-16214.out | 4 ++-- qpdf/qtest/qpdf/issue-119.out | 4 +--- qpdf/qtest/qpdf/issue-120.out | 8 +------- qpdf/qtest/qpdf/issue-143.out | 4 +--- qpdf/qtest/qpdf/issue-51.out | 13 +------------ qpdf/qtest/qpdf/job-api.out | 1 + qpdf/qtest/qpdf/test73.out | 4 ++-- qpdf/qtest/specific-bugs.test | 8 ++++---- qpdf/test_driver.cc | 2 +- 26 files changed, 31 insertions(+), 38 deletions(-) create mode 100644 fuzz/qpdf_extra/69857.fuzz diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index fed51355..75f0db5a 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -118,6 +118,7 @@ set(CORPUS_OTHER 68377.fuzz 68668.fuzz 68915.fuzz + 69857.fuzz ) set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus) diff --git a/fuzz/qpdf_extra/69857.fuzz b/fuzz/qpdf_extra/69857.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..345d32cff5a9526cab10112c21db9a15c6081067 GIT binary patch literal 53677 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 IFg5%C0ICZO 1], ['runlength' => 6], ['tiffpredictor' => 2], - ['qpdf' => 60], # increment when adding new files + ['qpdf' => 61], # increment when adding new files ); my $n_tests = 0; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index d43fec16..aab049cb 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -471,6 +471,10 @@ QPDF::parse(char const* password) initializeEncryption(); m->parsed = true; + if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) { + // QPDFs created from JSON have an empty xref table and no root object yet. + throw damagedPDF("", 0, "unable to find page tree"); + } } void diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index c2d988bd..39df8d27 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1121,7 +1121,6 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) } else if (obj.renumber == -1) { // This can happen if a specially constructed file indicates that an object stream is // inside itself. - QTC::TC("qpdf", "QPDFWriter ignore self-referential object stream"); } return; } else if (!m->linearized) { diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index fe7eb38a..3b82a8da 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -277,7 +277,6 @@ QPDF ignore first extra space in xref entry 0 QPDF ignore second extra space in xref entry 0 QPDF ignore length error xref entry 0 QPDF_encryption pad short parameter 0 -QPDFWriter ignore self-referential object stream 0 QPDFObjectHandle found old angle 1 QPDF_Stream special filters 3 QPDFTokenizer block long token 0 diff --git a/qpdf/qtest/invalid-objects.test b/qpdf/qtest/invalid-objects.test index 1ece3810..8f3aa58e 100644 --- a/qpdf/qtest/invalid-objects.test +++ b/qpdf/qtest/invalid-objects.test @@ -19,7 +19,7 @@ my $n_tests = 4; $td->runtest("closed input source", {$td->COMMAND => "test_driver 73 minimal.pdf"}, {$td->FILE => "test73.out", - $td->EXIT_STATUS => 2}, + $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); $td->runtest("empty object", diff --git a/qpdf/qtest/qpdf/bad11-recover.out b/qpdf/qtest/qpdf/bad11-recover.out index 05ed3eec..20e683ff 100644 --- a/qpdf/qtest/qpdf/bad11-recover.out +++ b/qpdf/qtest/qpdf/bad11-recover.out @@ -1,6 +1,7 @@ WARNING: bad11.pdf: file is damaged WARNING: bad11.pdf (trailer, offset 905): /Prev key in trailer dictionary is not an integer WARNING: bad11.pdf: Attempting to reconstruct cross-reference table +WARNING: bad11.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad12-recover.out b/qpdf/qtest/qpdf/bad12-recover.out index 503b957d..428460f7 100644 --- a/qpdf/qtest/qpdf/bad12-recover.out +++ b/qpdf/qtest/qpdf/bad12-recover.out @@ -1,4 +1,5 @@ WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7) +WARNING: bad12.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad12.out b/qpdf/qtest/qpdf/bad12.out index 9f4e4188..8904a33e 100644 --- a/qpdf/qtest/qpdf/bad12.out +++ b/qpdf/qtest/qpdf/bad12.out @@ -1,4 +1,5 @@ WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7) +WARNING: bad12.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad2-recover.out b/qpdf/qtest/qpdf/bad2-recover.out index 7b16b963..86e4eef8 100644 --- a/qpdf/qtest/qpdf/bad2-recover.out +++ b/qpdf/qtest/qpdf/bad2-recover.out @@ -1,6 +1,7 @@ WARNING: bad2.pdf: file is damaged WARNING: bad2.pdf: can't find startxref WARNING: bad2.pdf: Attempting to reconstruct cross-reference table +WARNING: bad2.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad3-recover.out b/qpdf/qtest/qpdf/bad3-recover.out index 1e84bc17..006e6d6b 100644 --- a/qpdf/qtest/qpdf/bad3-recover.out +++ b/qpdf/qtest/qpdf/bad3-recover.out @@ -1,6 +1,7 @@ WARNING: bad3.pdf: file is damaged WARNING: bad3.pdf (offset 542): xref not found WARNING: bad3.pdf: Attempting to reconstruct cross-reference table +WARNING: bad3.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad4-recover.out b/qpdf/qtest/qpdf/bad4-recover.out index 54d106c6..f138142b 100644 --- a/qpdf/qtest/qpdf/bad4-recover.out +++ b/qpdf/qtest/qpdf/bad4-recover.out @@ -1,6 +1,7 @@ WARNING: bad4.pdf: file is damaged WARNING: bad4.pdf (xref table, offset 547): xref syntax invalid WARNING: bad4.pdf: Attempting to reconstruct cross-reference table +WARNING: bad4.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad5-recover.out b/qpdf/qtest/qpdf/bad5-recover.out index f01fe4d4..b4cdc343 100644 --- a/qpdf/qtest/qpdf/bad5-recover.out +++ b/qpdf/qtest/qpdf/bad5-recover.out @@ -1,6 +1,7 @@ WARNING: bad5.pdf: file is damaged WARNING: bad5.pdf (xref table, offset 591): invalid xref entry (obj=2) WARNING: bad5.pdf: Attempting to reconstruct cross-reference table +WARNING: bad5.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad6-recover.out b/qpdf/qtest/qpdf/bad6-recover.out index 9a222c13..ec0b8e40 100644 --- a/qpdf/qtest/qpdf/bad6-recover.out +++ b/qpdf/qtest/qpdf/bad6-recover.out @@ -1,3 +1,4 @@ +WARNING: bad6.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad6.out b/qpdf/qtest/qpdf/bad6.out index 1d054ae5..a85b5198 100644 --- a/qpdf/qtest/qpdf/bad6.out +++ b/qpdf/qtest/qpdf/bad6.out @@ -1,3 +1,4 @@ +WARNING: bad6.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/bad8-recover.out b/qpdf/qtest/qpdf/bad8-recover.out index 2cd5daf3..b67fc3c7 100644 --- a/qpdf/qtest/qpdf/bad8-recover.out +++ b/qpdf/qtest/qpdf/bad8-recover.out @@ -1,6 +1,7 @@ WARNING: bad8.pdf: file is damaged WARNING: bad8.pdf (offset 543): xref not found WARNING: bad8.pdf: Attempting to reconstruct cross-reference table +WARNING: bad8.pdf (object 2 0, offset 128): expected endobj /QTest is implicit /QTest is direct and has type null (2) /QTest is null diff --git a/qpdf/qtest/qpdf/fuzz-16214.out b/qpdf/qtest/qpdf/fuzz-16214.out index 21957d35..a03574be 100644 --- a/qpdf/qtest/qpdf/fuzz-16214.out +++ b/qpdf/qtest/qpdf/fuzz-16214.out @@ -11,8 +11,8 @@ WARNING: fuzz-16214.pdf (object 1 0, offset 7189): expected n n obj WARNING: fuzz-16214.pdf: Attempting to reconstruct cross-reference table WARNING: fuzz-16214.pdf (offset 7207): error decoding stream data for object 2 0: stream inflate: inflate: data: invalid code lengths set WARNING: fuzz-16214.pdf (offset 7207): getStreamData called on unfilterable stream -WARNING: fuzz-16214.pdf (object 11 0, offset 11551): supposed object stream 5 has wrong type -WARNING: fuzz-16214.pdf (object 11 0, offset 11551): object stream 5 has incorrect keys +WARNING: fuzz-16214.pdf (object 8 0, offset 7207): supposed object stream 5 has wrong type +WARNING: fuzz-16214.pdf (object 8 0, offset 7207): object stream 5 has incorrect keys WARNING: fuzz-16214.pdf (object 21 0, offset 3639): expected endstream WARNING: fuzz-16214.pdf (object 21 0, offset 3112): attempting to recover stream length WARNING: fuzz-16214.pdf (object 21 0, offset 3112): recovered stream length: 340 diff --git a/qpdf/qtest/qpdf/issue-119.out b/qpdf/qtest/qpdf/issue-119.out index 45b92fed..6571b3fe 100644 --- a/qpdf/qtest/qpdf/issue-119.out +++ b/qpdf/qtest/qpdf/issue-119.out @@ -1,3 +1 @@ -WARNING: issue-119.pdf (object 4 0, offset 298): expected dictionary key but found non-name object; inserting key /QPDFFake1 -WARNING: issue-119.pdf (object 4 0, offset 298): expected dictionary key but found non-name object; inserting key /QPDFFake2 -qpdf: operation succeeded with warnings; resulting file may have some problems +qpdf: issue-119.pdf: unable to find page tree diff --git a/qpdf/qtest/qpdf/issue-120.out b/qpdf/qtest/qpdf/issue-120.out index ec32f9de..cc03ccfa 100644 --- a/qpdf/qtest/qpdf/issue-120.out +++ b/qpdf/qtest/qpdf/issue-120.out @@ -1,7 +1 @@ -WARNING: issue-120.pdf (offset 85): loop detected resolving object 3 0 -WARNING: issue-120.pdf (object 6 0, offset 85): supposed object stream 3 is not a stream -WARNING: issue-120.pdf: file is damaged -WARNING: issue-120.pdf (object 8 10, offset 26880): expected n n obj -WARNING: issue-120.pdf: Attempting to reconstruct cross-reference table -WARNING: issue-120.pdf: object 8 10 not found in file after regenerating cross reference table -qpdf: operation succeeded with warnings; resulting file may have some problems +qpdf: issue-120.pdf: unable to find page tree diff --git a/qpdf/qtest/qpdf/issue-143.out b/qpdf/qtest/qpdf/issue-143.out index 5dccc8ed..44144b4d 100644 --- a/qpdf/qtest/qpdf/issue-143.out +++ b/qpdf/qtest/qpdf/issue-143.out @@ -14,6 +14,4 @@ WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length WARNING: issue-143.pdf (object 1 0, offset 84): recovered stream length: 606 WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1 -WARNING: issue-143.pdf: object 0/0 has unexpected xref entry type -WARNING: issue-143.pdf (object 2 0, offset 84): supposed object stream 12336 is not a stream -qpdf: operation succeeded with warnings; resulting file may have some problems +qpdf: issue-143.pdf: unable to find page tree diff --git a/qpdf/qtest/qpdf/issue-51.out b/qpdf/qtest/qpdf/issue-51.out index 251df570..2777ab6f 100644 --- a/qpdf/qtest/qpdf/issue-51.out +++ b/qpdf/qtest/qpdf/issue-51.out @@ -2,15 +2,4 @@ WARNING: issue-51.pdf: can't find PDF header WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8) WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj -WARNING: issue-51.pdf (object 1 0, offset 236): dictionary has duplicated key /00000000; last occurrence overrides earlier ones -WARNING: issue-51.pdf (object 1 0, offset 359): expected endobj -WARNING: issue-51.pdf (offset 70): loop detected resolving object 2 0 -WARNING: issue-51.pdf (object 2 0, offset 26): stream dictionary lacks /Length key -WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length -WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty -WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj -WARNING: issue-51.pdf (object 3 0): object has offset 0 -WARNING: issue-51.pdf (object 4 0): object has offset 0 -WARNING: issue-51.pdf (object 5 0): object has offset 0 -WARNING: issue-51.pdf (object 6 0): object has offset 0 -WARNING: issue-51.pdf (object 8 0): object has offset 0 +issue-51.pdf: unable to find page tree diff --git a/qpdf/qtest/qpdf/job-api.out b/qpdf/qtest/qpdf/job-api.out index 7ef99171..09db7306 100644 --- a/qpdf/qtest/qpdf/job-api.out +++ b/qpdf/qtest/qpdf/job-api.out @@ -21,6 +21,7 @@ captured stderr WARNING: bad2.pdf: file is damaged WARNING: bad2.pdf: can't find startxref WARNING: bad2.pdf: Attempting to reconstruct cross-reference table +WARNING: bad2.pdf (object 2 0, offset 128): expected endobj WARNING: bad2.pdf (object 4 0, offset 389): expected endobj qpdf: operation succeeded with warnings test 84 done diff --git a/qpdf/qtest/qpdf/test73.out b/qpdf/qtest/qpdf/test73.out index b23c4c00..ad6fb785 100644 --- a/qpdf/qtest/qpdf/test73.out +++ b/qpdf/qtest/qpdf/test73.out @@ -1,3 +1,3 @@ getRoot: attempted to dereference an uninitialized QPDFObjectHandle -WARNING: closed input source: object 1/0: error reading object: QPDF operation attempted on a QPDF object with no input source. QPDF operations are invalid before processFile (or another process method) or after closeInputSource -closed input source: unable to find /Root dictionary +WARNING: closed input source: object 4/0: error reading object: QPDF operation attempted on a QPDF object with no input source. QPDF operations are invalid before processFile (or another process method) or after closeInputSource +test 73 done diff --git a/qpdf/qtest/specific-bugs.test b/qpdf/qtest/specific-bugs.test index 326b3e98..15c9e01d 100644 --- a/qpdf/qtest/specific-bugs.test +++ b/qpdf/qtest/specific-bugs.test @@ -16,19 +16,19 @@ my $td = new TestDriver('specific-bugs'); # The number is the github issue number in which the bug was reported. my @bug_tests = ( - ["51", "resolve loop", 3], + ["51", "resolve loop", 2], ["99", "object 0", 2], ["99b", "object 0", 2], ["100", "xref reconstruction loop", 2], ["101", "resolve for exception text", 2], ["117", "other infinite loop", 3], ["118", "other infinite loop", 2], - ["119", "other infinite loop", 3], - ["120", "other infinite loop", 3], + ["119", "other infinite loop", 2], + ["120", "other infinite loop", 2], ["106", "zlib data error", 3], ["141a", "/W entry size 0", 2], ["141b", "/W entry size 0", 2], - ["143", "self-referential ostream", 3, "--preserve-unreferenced"], + ["143", "self-referential ostream", 2, "--preserve-unreferenced"], ["146", "very deeply nested array", 2], ["147", "previously caused memory error", 2], ["148", "free memory on bad flate", 2], diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 0f15f506..fd50cbce 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -2496,7 +2496,7 @@ test_73(QPDF& pdf, char const* arg2) } pdf.closeInputSource(); - pdf.getRoot().getKey("/Pages").unparseResolved(); + pdf.getObject(4, 0).unparseResolved(); } static void