From 47a38a942d34a65524dca2e1255c1b4ba02d7eb6 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Wed, 28 Aug 2019 09:32:58 -0400 Subject: [PATCH] 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 | 1 + fuzz/qtest/fuzz.test | 2 +- libqpdf/QPDFWriter.cc | 14 +++++++++++++- libqpdf/QPDF_Stream.cc | 3 ++- qpdf/qpdf.testcov | 1 + qpdf/qtest/qpdf.test | 6 ++++-- qpdf/qtest/qpdf/fuzz-16214.out | 22 ++++++++++++++++++++++ qpdf/qtest/qpdf/fuzz-16214.pdf | Bin 0 -> 12142 bytes 8 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 qpdf/qtest/qpdf/fuzz-16214.out create mode 100644 qpdf/qtest/qpdf/fuzz-16214.pdf diff --git a/fuzz/build.mk b/fuzz/build.mk index ec3bd61e..d38fb909 100644 --- a/fuzz/build.mk +++ b/fuzz/build.mk @@ -41,6 +41,7 @@ CORPUS_FROM_TEST = \ outlines-with-old-root-dests.pdf \ page-labels-and-outlines.pdf \ page-labels-num-tree.pdf \ + fuzz-16214.pdf \ issue-99b.pdf \ issue-99.pdf \ issue-100.pdf \ diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index 26ae4f10..df850c45 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -9,7 +9,7 @@ require TestDriver; my $td = new TestDriver('fuzz'); -my $qpdf_n_test_files = 29; +my $qpdf_n_test_files = 30; my @extra = glob("../qpdf_extra/*.fuzz"); my $qpdf_n_extra_files = scalar(@extra); my $qpdf_n_orig_files = 2559; diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 895f98ce..f5fa2bc9 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -2012,7 +2012,19 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) // pass 1. indicateProgress(true, false); } - writeObject(this->m->pdf.getObjectByObjGen(obj), count); + QPDFObjectHandle obj_to_write = + this->m->pdf.getObjectByObjGen(obj); + if (obj_to_write.isStream()) + { + // This condition occurred in a fuzz input. Ideally we + // should block it at at parse time, but it's not + // clear to me how to construct a case for this. + QTC::TC("qpdf", "QPDFWriter stream in ostream"); + obj_to_write.warnIfPossible( + "stream found inside object stream; treating as null"); + obj_to_write = QPDFObjectHandle::newNull(); + } + writeObject(obj_to_write, count); this->m->xref[new_obj] = QPDFXRefEntry(2, new_id, count); } diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 4f20c604..dd2796e8 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -105,7 +105,8 @@ QPDF_Stream::setStreamDescription() { setDescription( this->qpdf, - "stream object " + QUtil::int_to_string(this->objid) + " " + + this->qpdf->getFilename() + + ", stream object " + QUtil::int_to_string(this->objid) + " " + QUtil::int_to_string(this->generation)); } diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index c8ad0bdd..f327d464 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -444,3 +444,4 @@ QPDF xref skipped space 0 QPDF eof skipping spaces before xref 1 QPDF_encryption user matches owner V < 5 0 QPDF_encryption same password 1 +QPDFWriter stream in ostream 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 00f29c72..41c94519 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -643,6 +643,7 @@ my @bug_tests = ( ["263", "empty xref stream", 2], ["335a", "ozz-fuzz-12152", 2], ["335b", "ozz-fuzz-14845", 2], + ["fuzz-16214", "stream in object stream", 3], # When adding to this list, consider adding to SEED_CORPUS_FILES # in fuzz/build.mk and updating the count in fuzz/qtest/fuzz.test. ); @@ -669,9 +670,10 @@ foreach my $d (@bug_tests) } else { + my $base = (-f "issue-$n.pdf") ? "issue-$n" : "$n"; $td->runtest($description, - {$td->COMMAND => "qpdf issue-$n.pdf a.pdf"}, - {$td->FILE => "issue-$n.out", + {$td->COMMAND => "qpdf $base.pdf a.pdf"}, + {$td->FILE => "$base.out", $td->EXIT_STATUS => $exit_status}, $td->NORMALIZE_NEWLINES); } diff --git a/qpdf/qtest/qpdf/fuzz-16214.out b/qpdf/qtest/qpdf/fuzz-16214.out new file mode 100644 index 00000000..55862b1a --- /dev/null +++ b/qpdf/qtest/qpdf/fuzz-16214.out @@ -0,0 +1,22 @@ +WARNING: fuzz-16214.pdf: can't find PDF header +WARNING: fuzz-16214.pdf (xref stream: object 5 0, offset 124): stream dictionary lacks /Length key +WARNING: fuzz-16214.pdf (xref stream: object 5 0, offset 353): attempting to recover stream length +WARNING: fuzz-16214.pdf (xref stream: object 5 0, offset 353): recovered stream length: 722 +WARNING: fuzz-16214.pdf (xref stream, offset 116): Cross-reference stream data has the wrong size; expected = 92; actual = 196 +WARNING: fuzz-16214.pdf: reported number of objects (6) is not one plus the highest object number (35) +WARNING: fuzz-16214.pdf (object 14 0, offset 652): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: fuzz-16214.pdf (object 14 0, offset 734): expected endobj +WARNING: fuzz-16214.pdf: file is damaged +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 (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 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 +WARNING: fuzz-16214.pdf, stream object 8 0: stream found inside object stream; treating as null +WARNING: fuzz-16214.pdf, stream object 8 0: stream found inside object stream; treating as null +qpdf: operation succeeded with warnings; resulting file may have some problems diff --git a/qpdf/qtest/qpdf/fuzz-16214.pdf b/qpdf/qtest/qpdf/fuzz-16214.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c84a8eba6aca74cc1bd078861ca8e2f1dd3bf0d0 GIT binary patch literal 12142 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 PibNWU!eCZT)}sFh0Sj&7 literal 0 HcmV?d00001