Commit 47a38a942d34a65524dca2e1255c1b4ba02d7eb6

Authored by Jay Berkenbilt
1 parent 15248aa5

Detect stream in object stream, fixing fuzz 16214

It's detected in QPDFWriter instead of at parse time because I can't
figure out how to construct a test case in a reasonable time. This
commit moves the fuzz file into the regular test suite for a QTC
coverage case.
fuzz/build.mk
@@ -41,6 +41,7 @@ CORPUS_FROM_TEST = \ @@ -41,6 +41,7 @@ CORPUS_FROM_TEST = \
41 outlines-with-old-root-dests.pdf \ 41 outlines-with-old-root-dests.pdf \
42 page-labels-and-outlines.pdf \ 42 page-labels-and-outlines.pdf \
43 page-labels-num-tree.pdf \ 43 page-labels-num-tree.pdf \
  44 + fuzz-16214.pdf \
44 issue-99b.pdf \ 45 issue-99b.pdf \
45 issue-99.pdf \ 46 issue-99.pdf \
46 issue-100.pdf \ 47 issue-100.pdf \
fuzz/qtest/fuzz.test
@@ -9,7 +9,7 @@ require TestDriver; @@ -9,7 +9,7 @@ require TestDriver;
9 9
10 my $td = new TestDriver('fuzz'); 10 my $td = new TestDriver('fuzz');
11 11
12 -my $qpdf_n_test_files = 29; 12 +my $qpdf_n_test_files = 30;
13 my @extra = glob("../qpdf_extra/*.fuzz"); 13 my @extra = glob("../qpdf_extra/*.fuzz");
14 my $qpdf_n_extra_files = scalar(@extra); 14 my $qpdf_n_extra_files = scalar(@extra);
15 my $qpdf_n_orig_files = 2559; 15 my $qpdf_n_orig_files = 2559;
libqpdf/QPDFWriter.cc
@@ -2012,7 +2012,19 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -2012,7 +2012,19 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
2012 // pass 1. 2012 // pass 1.
2013 indicateProgress(true, false); 2013 indicateProgress(true, false);
2014 } 2014 }
2015 - writeObject(this->m->pdf.getObjectByObjGen(obj), count); 2015 + QPDFObjectHandle obj_to_write =
  2016 + this->m->pdf.getObjectByObjGen(obj);
  2017 + if (obj_to_write.isStream())
  2018 + {
  2019 + // This condition occurred in a fuzz input. Ideally we
  2020 + // should block it at at parse time, but it's not
  2021 + // clear to me how to construct a case for this.
  2022 + QTC::TC("qpdf", "QPDFWriter stream in ostream");
  2023 + obj_to_write.warnIfPossible(
  2024 + "stream found inside object stream; treating as null");
  2025 + obj_to_write = QPDFObjectHandle::newNull();
  2026 + }
  2027 + writeObject(obj_to_write, count);
2016 2028
2017 this->m->xref[new_obj] = QPDFXRefEntry(2, new_id, count); 2029 this->m->xref[new_obj] = QPDFXRefEntry(2, new_id, count);
2018 } 2030 }
libqpdf/QPDF_Stream.cc
@@ -105,7 +105,8 @@ QPDF_Stream::setStreamDescription() @@ -105,7 +105,8 @@ QPDF_Stream::setStreamDescription()
105 { 105 {
106 setDescription( 106 setDescription(
107 this->qpdf, 107 this->qpdf,
108 - "stream object " + QUtil::int_to_string(this->objid) + " " + 108 + this->qpdf->getFilename() +
  109 + ", stream object " + QUtil::int_to_string(this->objid) + " " +
109 QUtil::int_to_string(this->generation)); 110 QUtil::int_to_string(this->generation));
110 } 111 }
111 112
qpdf/qpdf.testcov
@@ -444,3 +444,4 @@ QPDF xref skipped space 0 @@ -444,3 +444,4 @@ QPDF xref skipped space 0
444 QPDF eof skipping spaces before xref 1 444 QPDF eof skipping spaces before xref 1
445 QPDF_encryption user matches owner V < 5 0 445 QPDF_encryption user matches owner V < 5 0
446 QPDF_encryption same password 1 446 QPDF_encryption same password 1
  447 +QPDFWriter stream in ostream 0
qpdf/qtest/qpdf.test
@@ -643,6 +643,7 @@ my @bug_tests = ( @@ -643,6 +643,7 @@ my @bug_tests = (
643 ["263", "empty xref stream", 2], 643 ["263", "empty xref stream", 2],
644 ["335a", "ozz-fuzz-12152", 2], 644 ["335a", "ozz-fuzz-12152", 2],
645 ["335b", "ozz-fuzz-14845", 2], 645 ["335b", "ozz-fuzz-14845", 2],
  646 + ["fuzz-16214", "stream in object stream", 3],
646 # When adding to this list, consider adding to SEED_CORPUS_FILES 647 # When adding to this list, consider adding to SEED_CORPUS_FILES
647 # in fuzz/build.mk and updating the count in fuzz/qtest/fuzz.test. 648 # in fuzz/build.mk and updating the count in fuzz/qtest/fuzz.test.
648 ); 649 );
@@ -669,9 +670,10 @@ foreach my $d (@bug_tests) @@ -669,9 +670,10 @@ foreach my $d (@bug_tests)
669 } 670 }
670 else 671 else
671 { 672 {
  673 + my $base = (-f "issue-$n.pdf") ? "issue-$n" : "$n";
672 $td->runtest($description, 674 $td->runtest($description,
673 - {$td->COMMAND => "qpdf issue-$n.pdf a.pdf"},  
674 - {$td->FILE => "issue-$n.out", 675 + {$td->COMMAND => "qpdf $base.pdf a.pdf"},
  676 + {$td->FILE => "$base.out",
675 $td->EXIT_STATUS => $exit_status}, 677 $td->EXIT_STATUS => $exit_status},
676 $td->NORMALIZE_NEWLINES); 678 $td->NORMALIZE_NEWLINES);
677 } 679 }
qpdf/qtest/qpdf/fuzz-16214.out 0 → 100644
  1 +WARNING: fuzz-16214.pdf: can't find PDF header
  2 +WARNING: fuzz-16214.pdf (xref stream: object 5 0, offset 124): stream dictionary lacks /Length key
  3 +WARNING: fuzz-16214.pdf (xref stream: object 5 0, offset 353): attempting to recover stream length
  4 +WARNING: fuzz-16214.pdf (xref stream: object 5 0, offset 353): recovered stream length: 722
  5 +WARNING: fuzz-16214.pdf (xref stream, offset 116): Cross-reference stream data has the wrong size; expected = 92; actual = 196
  6 +WARNING: fuzz-16214.pdf: reported number of objects (6) is not one plus the highest object number (35)
  7 +WARNING: fuzz-16214.pdf (object 14 0, offset 652): expected dictionary key but found non-name object; inserting key /QPDFFake1
  8 +WARNING: fuzz-16214.pdf (object 14 0, offset 734): expected endobj
  9 +WARNING: fuzz-16214.pdf: file is damaged
  10 +WARNING: fuzz-16214.pdf (object 1 0, offset 7189): expected n n obj
  11 +WARNING: fuzz-16214.pdf: Attempting to reconstruct cross-reference table
  12 +WARNING: fuzz-16214.pdf (offset 7207): error decoding stream data for object 2 0: stream inflate: inflate: data: invalid code lengths set
  13 +WARNING: fuzz-16214.pdf (offset 7207): getStreamData called on unfilterable stream
  14 +WARNING: fuzz-16214.pdf (offset 7207): error decoding stream data for object 2 0: stream inflate: inflate: data: invalid code lengths set
  15 +WARNING: fuzz-16214.pdf (offset 7207): getStreamData called on unfilterable stream
  16 +WARNING: fuzz-16214.pdf (object 11 0, offset 11551): supposed object stream 5 has wrong type
  17 +WARNING: fuzz-16214.pdf (object 21 0, offset 3639): expected endstream
  18 +WARNING: fuzz-16214.pdf (object 21 0, offset 3112): attempting to recover stream length
  19 +WARNING: fuzz-16214.pdf (object 21 0, offset 3112): recovered stream length: 340
  20 +WARNING: fuzz-16214.pdf, stream object 8 0: stream found inside object stream; treating as null
  21 +WARNING: fuzz-16214.pdf, stream object 8 0: stream found inside object stream; treating as null
  22 +qpdf: operation succeeded with warnings; resulting file may have some problems
qpdf/qtest/qpdf/fuzz-16214.pdf 0 → 100644
No preview for this file type