Commit e62973d277c57d8cc0a70c27afe0eb4958b78c42

Authored by m-holger
1 parent fff205dc

In QPDF check for page tree after reading xref table

Also add new fuzz test case.
fuzz/CMakeLists.txt
... ... @@ -118,6 +118,7 @@ set(CORPUS_OTHER
118 118 68377.fuzz
119 119 68668.fuzz
120 120 68915.fuzz
  121 + 69857.fuzz
121 122 )
122 123  
123 124 set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus)
... ...
fuzz/qpdf_extra/69857.fuzz 0 → 100644
No preview for this file type
fuzz/qtest/fuzz.test
... ... @@ -21,7 +21,7 @@ my @fuzzers = (
21 21 ['pngpredictor' => 1],
22 22 ['runlength' => 6],
23 23 ['tiffpredictor' => 2],
24   - ['qpdf' => 60], # increment when adding new files
  24 + ['qpdf' => 61], # increment when adding new files
25 25 );
26 26  
27 27 my $n_tests = 0;
... ...
libqpdf/QPDF.cc
... ... @@ -471,6 +471,10 @@ QPDF::parse(char const* password)
471 471  
472 472 initializeEncryption();
473 473 m->parsed = true;
  474 + if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) {
  475 + // QPDFs created from JSON have an empty xref table and no root object yet.
  476 + throw damagedPDF("", 0, "unable to find page tree");
  477 + }
474 478 }
475 479  
476 480 void
... ...
libqpdf/QPDFWriter.cc
... ... @@ -1121,7 +1121,6 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
1121 1121 } else if (obj.renumber == -1) {
1122 1122 // This can happen if a specially constructed file indicates that an object stream is
1123 1123 // inside itself.
1124   - QTC::TC("qpdf", "QPDFWriter ignore self-referential object stream");
1125 1124 }
1126 1125 return;
1127 1126 } else if (!m->linearized) {
... ...
qpdf/qpdf.testcov
... ... @@ -277,7 +277,6 @@ QPDF ignore first extra space in xref entry 0
277 277 QPDF ignore second extra space in xref entry 0
278 278 QPDF ignore length error xref entry 0
279 279 QPDF_encryption pad short parameter 0
280   -QPDFWriter ignore self-referential object stream 0
281 280 QPDFObjectHandle found old angle 1
282 281 QPDF_Stream special filters 3
283 282 QPDFTokenizer block long token 0
... ...
qpdf/qtest/invalid-objects.test
... ... @@ -19,7 +19,7 @@ my $n_tests = 4;
19 19 $td->runtest("closed input source",
20 20 {$td->COMMAND => "test_driver 73 minimal.pdf"},
21 21 {$td->FILE => "test73.out",
22   - $td->EXIT_STATUS => 2},
  22 + $td->EXIT_STATUS => 0},
23 23 $td->NORMALIZE_NEWLINES);
24 24  
25 25 $td->runtest("empty object",
... ...
qpdf/qtest/qpdf/bad11-recover.out
1 1 WARNING: bad11.pdf: file is damaged
2 2 WARNING: bad11.pdf (trailer, offset 905): /Prev key in trailer dictionary is not an integer
3 3 WARNING: bad11.pdf: Attempting to reconstruct cross-reference table
  4 +WARNING: bad11.pdf (object 2 0, offset 128): expected endobj
4 5 /QTest is implicit
5 6 /QTest is direct and has type null (2)
6 7 /QTest is null
... ...
qpdf/qtest/qpdf/bad12-recover.out
1 1 WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7)
  2 +WARNING: bad12.pdf (object 2 0, offset 128): expected endobj
2 3 /QTest is implicit
3 4 /QTest is direct and has type null (2)
4 5 /QTest is null
... ...
qpdf/qtest/qpdf/bad12.out
1 1 WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7)
  2 +WARNING: bad12.pdf (object 2 0, offset 128): expected endobj
2 3 /QTest is implicit
3 4 /QTest is direct and has type null (2)
4 5 /QTest is null
... ...
qpdf/qtest/qpdf/bad2-recover.out
1 1 WARNING: bad2.pdf: file is damaged
2 2 WARNING: bad2.pdf: can't find startxref
3 3 WARNING: bad2.pdf: Attempting to reconstruct cross-reference table
  4 +WARNING: bad2.pdf (object 2 0, offset 128): expected endobj
4 5 /QTest is implicit
5 6 /QTest is direct and has type null (2)
6 7 /QTest is null
... ...
qpdf/qtest/qpdf/bad3-recover.out
1 1 WARNING: bad3.pdf: file is damaged
2 2 WARNING: bad3.pdf (offset 542): xref not found
3 3 WARNING: bad3.pdf: Attempting to reconstruct cross-reference table
  4 +WARNING: bad3.pdf (object 2 0, offset 128): expected endobj
4 5 /QTest is implicit
5 6 /QTest is direct and has type null (2)
6 7 /QTest is null
... ...
qpdf/qtest/qpdf/bad4-recover.out
1 1 WARNING: bad4.pdf: file is damaged
2 2 WARNING: bad4.pdf (xref table, offset 547): xref syntax invalid
3 3 WARNING: bad4.pdf: Attempting to reconstruct cross-reference table
  4 +WARNING: bad4.pdf (object 2 0, offset 128): expected endobj
4 5 /QTest is implicit
5 6 /QTest is direct and has type null (2)
6 7 /QTest is null
... ...
qpdf/qtest/qpdf/bad5-recover.out
1 1 WARNING: bad5.pdf: file is damaged
2 2 WARNING: bad5.pdf (xref table, offset 591): invalid xref entry (obj=2)
3 3 WARNING: bad5.pdf: Attempting to reconstruct cross-reference table
  4 +WARNING: bad5.pdf (object 2 0, offset 128): expected endobj
4 5 /QTest is implicit
5 6 /QTest is direct and has type null (2)
6 7 /QTest is null
... ...
qpdf/qtest/qpdf/bad6-recover.out
  1 +WARNING: bad6.pdf (object 2 0, offset 128): expected endobj
1 2 /QTest is implicit
2 3 /QTest is direct and has type null (2)
3 4 /QTest is null
... ...
qpdf/qtest/qpdf/bad6.out
  1 +WARNING: bad6.pdf (object 2 0, offset 128): expected endobj
1 2 /QTest is implicit
2 3 /QTest is direct and has type null (2)
3 4 /QTest is null
... ...
qpdf/qtest/qpdf/bad8-recover.out
1 1 WARNING: bad8.pdf: file is damaged
2 2 WARNING: bad8.pdf (offset 543): xref not found
3 3 WARNING: bad8.pdf: Attempting to reconstruct cross-reference table
  4 +WARNING: bad8.pdf (object 2 0, offset 128): expected endobj
4 5 /QTest is implicit
5 6 /QTest is direct and has type null (2)
6 7 /QTest is null
... ...
qpdf/qtest/qpdf/fuzz-16214.out
... ... @@ -11,8 +11,8 @@ WARNING: fuzz-16214.pdf (object 1 0, offset 7189): expected n n obj
11 11 WARNING: fuzz-16214.pdf: Attempting to reconstruct cross-reference table
12 12 WARNING: fuzz-16214.pdf (offset 7207): error decoding stream data for object 2 0: stream inflate: inflate: data: invalid code lengths set
13 13 WARNING: fuzz-16214.pdf (offset 7207): getStreamData called on unfilterable stream
14   -WARNING: fuzz-16214.pdf (object 11 0, offset 11551): supposed object stream 5 has wrong type
15   -WARNING: fuzz-16214.pdf (object 11 0, offset 11551): object stream 5 has incorrect keys
  14 +WARNING: fuzz-16214.pdf (object 8 0, offset 7207): supposed object stream 5 has wrong type
  15 +WARNING: fuzz-16214.pdf (object 8 0, offset 7207): object stream 5 has incorrect keys
16 16 WARNING: fuzz-16214.pdf (object 21 0, offset 3639): expected endstream
17 17 WARNING: fuzz-16214.pdf (object 21 0, offset 3112): attempting to recover stream length
18 18 WARNING: fuzz-16214.pdf (object 21 0, offset 3112): recovered stream length: 340
... ...
qpdf/qtest/qpdf/issue-119.out
1   -WARNING: issue-119.pdf (object 4 0, offset 298): expected dictionary key but found non-name object; inserting key /QPDFFake1
2   -WARNING: issue-119.pdf (object 4 0, offset 298): expected dictionary key but found non-name object; inserting key /QPDFFake2
3   -qpdf: operation succeeded with warnings; resulting file may have some problems
  1 +qpdf: issue-119.pdf: unable to find page tree
... ...
qpdf/qtest/qpdf/issue-120.out
1   -WARNING: issue-120.pdf (offset 85): loop detected resolving object 3 0
2   -WARNING: issue-120.pdf (object 6 0, offset 85): supposed object stream 3 is not a stream
3   -WARNING: issue-120.pdf: file is damaged
4   -WARNING: issue-120.pdf (object 8 10, offset 26880): expected n n obj
5   -WARNING: issue-120.pdf: Attempting to reconstruct cross-reference table
6   -WARNING: issue-120.pdf: object 8 10 not found in file after regenerating cross reference table
7   -qpdf: operation succeeded with warnings; resulting file may have some problems
  1 +qpdf: issue-120.pdf: unable to find page tree
... ...
qpdf/qtest/qpdf/issue-143.out
... ... @@ -14,6 +14,4 @@ WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length
14 14 WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length
15 15 WARNING: issue-143.pdf (object 1 0, offset 84): recovered stream length: 606
16 16 WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1
17   -WARNING: issue-143.pdf: object 0/0 has unexpected xref entry type
18   -WARNING: issue-143.pdf (object 2 0, offset 84): supposed object stream 12336 is not a stream
19   -qpdf: operation succeeded with warnings; resulting file may have some problems
  17 +qpdf: issue-143.pdf: unable to find page tree
... ...
qpdf/qtest/qpdf/issue-51.out
... ... @@ -2,15 +2,4 @@ WARNING: issue-51.pdf: can't find PDF header
2 2 WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8)
3 3 WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones
4 4 WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj
5   -WARNING: issue-51.pdf (object 1 0, offset 236): dictionary has duplicated key /00000000; last occurrence overrides earlier ones
6   -WARNING: issue-51.pdf (object 1 0, offset 359): expected endobj
7   -WARNING: issue-51.pdf (offset 70): loop detected resolving object 2 0
8   -WARNING: issue-51.pdf (object 2 0, offset 26): stream dictionary lacks /Length key
9   -WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length
10   -WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty
11   -WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj
12   -WARNING: issue-51.pdf (object 3 0): object has offset 0
13   -WARNING: issue-51.pdf (object 4 0): object has offset 0
14   -WARNING: issue-51.pdf (object 5 0): object has offset 0
15   -WARNING: issue-51.pdf (object 6 0): object has offset 0
16   -WARNING: issue-51.pdf (object 8 0): object has offset 0
  5 +issue-51.pdf: unable to find page tree
... ...
qpdf/qtest/qpdf/job-api.out
... ... @@ -21,6 +21,7 @@ captured stderr
21 21 WARNING: bad2.pdf: file is damaged
22 22 WARNING: bad2.pdf: can't find startxref
23 23 WARNING: bad2.pdf: Attempting to reconstruct cross-reference table
  24 +WARNING: bad2.pdf (object 2 0, offset 128): expected endobj
24 25 WARNING: bad2.pdf (object 4 0, offset 389): expected endobj
25 26 qpdf: operation succeeded with warnings
26 27 test 84 done
... ...
qpdf/qtest/qpdf/test73.out
1 1 getRoot: attempted to dereference an uninitialized QPDFObjectHandle
2   -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
3   -closed input source: unable to find /Root dictionary
  2 +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
  3 +test 73 done
... ...
qpdf/qtest/specific-bugs.test
... ... @@ -16,19 +16,19 @@ my $td = new TestDriver('specific-bugs');
16 16  
17 17 # The number is the github issue number in which the bug was reported.
18 18 my @bug_tests = (
19   - ["51", "resolve loop", 3],
  19 + ["51", "resolve loop", 2],
20 20 ["99", "object 0", 2],
21 21 ["99b", "object 0", 2],
22 22 ["100", "xref reconstruction loop", 2],
23 23 ["101", "resolve for exception text", 2],
24 24 ["117", "other infinite loop", 3],
25 25 ["118", "other infinite loop", 2],
26   - ["119", "other infinite loop", 3],
27   - ["120", "other infinite loop", 3],
  26 + ["119", "other infinite loop", 2],
  27 + ["120", "other infinite loop", 2],
28 28 ["106", "zlib data error", 3],
29 29 ["141a", "/W entry size 0", 2],
30 30 ["141b", "/W entry size 0", 2],
31   - ["143", "self-referential ostream", 3, "--preserve-unreferenced"],
  31 + ["143", "self-referential ostream", 2, "--preserve-unreferenced"],
32 32 ["146", "very deeply nested array", 2],
33 33 ["147", "previously caused memory error", 2],
34 34 ["148", "free memory on bad flate", 2],
... ...
qpdf/test_driver.cc
... ... @@ -2496,7 +2496,7 @@ test_73(QPDF& pdf, char const* arg2)
2496 2496 }
2497 2497  
2498 2498 pdf.closeInputSource();
2499   - pdf.getRoot().getKey("/Pages").unparseResolved();
  2499 + pdf.getObject(4, 0).unparseResolved();
2500 2500 }
2501 2501  
2502 2502 static void
... ...