diff options
author | Jay Berkenbilt <ejb@ql.org> | 2017-07-25 16:21:27 +0200 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2017-07-26 12:24:07 +0200 |
commit | 315092dd98d5230ef0efa18b294d464d0e9f79d0 (patch) | |
tree | c0031a373dd87c04d2d34f2fbcd7602b344c4ac2 | |
parent | 603f222365252f1a1e20303b3dbe52466be3053b (diff) | |
download | qpdf-315092dd98d5230ef0efa18b294d464d0e9f79d0.tar.zst |
Avoid xref reconstruction infinite loop (fixes #100)
This is CVE-2017-9209.
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | include/qpdf/QPDF.hh | 1 | ||||
-rw-r--r-- | libqpdf/QPDF.cc | 10 | ||||
-rw-r--r-- | qpdf/qtest/qpdf.test | 3 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/issue-100.out | 5 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/issue-100.pdf | bin | 0 -> 1145 bytes |
6 files changed, 22 insertions, 1 deletions
@@ -1,5 +1,9 @@ 2017-07-26 Jay Berkenbilt <ejb@ql.org> + * 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<QPDFObjGen> 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 Binary files differnew file mode 100644 index 00000000..fc418b3b --- /dev/null +++ b/qpdf/qtest/qpdf/issue-100.pdf |