Commit 47a38a942d34a65524dca2e1255c1b4ba02d7eb6
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.
Showing
8 changed files
with
44 additions
and
5 deletions
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