diff --git a/ChangeLog b/ChangeLog index 32bafad6..ce0ce1e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2017-07-26 Jay Berkenbilt + * CVE-2017-9209: Fix infinite loop caused by attempting to + reconstruct the xref table while already in the process of + reconstructing the xref table. + * CVE-2017-9210: Fix infinite loop caused by attempting to unparse an object for inclusion in the text of an exception. diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 88acf6c5..f7a31edf 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1075,6 +1075,7 @@ class QPDF // copied_stream_data_provider is owned by copied_streams CopiedStreamDataProvider* copied_stream_data_provider; std::set attachment_streams; + bool reconstructed_xref; // Linearization data qpdf_offset_t first_xref_item_offset; // actual value from file diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index b8a1601c..a50c87ad 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -93,6 +93,7 @@ QPDF::QPDF() : cached_key_generation(0), pushed_inherited_attributes_to_pages(false), copied_stream_data_provider(0), + reconstructed_xref(false), first_xref_item_offset(0), uncompressed_after_compressed(false) { @@ -331,6 +332,15 @@ QPDF::setTrailer(QPDFObjectHandle obj) void QPDF::reconstruct_xref(QPDFExc& e) { + if (this->reconstructed_xref) + { + // Avoid xref reconstruction infinite loops + QTC::TC("qpdf", "QPDF caught recursive xref reconstruction"); + throw e; + } + + this->reconstructed_xref = true; + PCRE obj_re("^\\s*(\\d+)\\s+(\\d+)\\s+obj\\b"); PCRE endobj_re("^\\s*endobj\\b"); PCRE trailer_re("^\\s*trailer\\b"); diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index e0b2609a..dd8dad30 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -206,7 +206,7 @@ $td->runtest("remove page we don't have", show_ntests(); # ---------- $td->notify("--- Miscellaneous Tests ---"); -$n_tests += 78; +$n_tests += 79; $td->runtest("qpdf version", {$td->COMMAND => "qpdf --version"}, @@ -220,6 +220,7 @@ $td->runtest("C API: qpdf version", # Files to reproduce various bugs foreach my $d ( + ["100","xref reconstruction loop"], ["101", "resolve for exception text"], ) { diff --git a/qpdf/qtest/qpdf/issue-100.out b/qpdf/qtest/qpdf/issue-100.out new file mode 100644 index 00000000..37bd3207 --- /dev/null +++ b/qpdf/qtest/qpdf/issue-100.out @@ -0,0 +1,5 @@ +WARNING: issue-100.pdf: file is damaged +WARNING: issue-100.pdf (file position 736): xref not found +WARNING: issue-100.pdf: Attempting to reconstruct cross-reference table +WARNING: issue-100.pdf (object 5 0, file position 489): attempting to recover stream length +issue-100.pdf (object 6 0, file position 59): expected n n obj diff --git a/qpdf/qtest/qpdf/issue-100.pdf b/qpdf/qtest/qpdf/issue-100.pdf new file mode 100644 index 00000000..fc418b3b Binary files /dev/null and b/qpdf/qtest/qpdf/issue-100.pdf differ