Commit 315092dd98d5230ef0efa18b294d464d0e9f79d0
1 parent
603f2223
Avoid xref reconstruction infinite loop (fixes #100)
This is CVE-2017-9209.
Showing
6 changed files
with
22 additions
and
1 deletions
ChangeLog
| 1 | 2017-07-26 Jay Berkenbilt <ejb@ql.org> | 1 | 2017-07-26 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | ||
| 3 | + * CVE-2017-9209: Fix infinite loop caused by attempting to | ||
| 4 | + reconstruct the xref table while already in the process of | ||
| 5 | + reconstructing the xref table. | ||
| 6 | + | ||
| 3 | * CVE-2017-9210: Fix infinite loop caused by attempting to unparse | 7 | * CVE-2017-9210: Fix infinite loop caused by attempting to unparse |
| 4 | an object for inclusion in the text of an exception. | 8 | an object for inclusion in the text of an exception. |
| 5 | 9 |
include/qpdf/QPDF.hh
| @@ -1075,6 +1075,7 @@ class QPDF | @@ -1075,6 +1075,7 @@ class QPDF | ||
| 1075 | // copied_stream_data_provider is owned by copied_streams | 1075 | // copied_stream_data_provider is owned by copied_streams |
| 1076 | CopiedStreamDataProvider* copied_stream_data_provider; | 1076 | CopiedStreamDataProvider* copied_stream_data_provider; |
| 1077 | std::set<QPDFObjGen> attachment_streams; | 1077 | std::set<QPDFObjGen> attachment_streams; |
| 1078 | + bool reconstructed_xref; | ||
| 1078 | 1079 | ||
| 1079 | // Linearization data | 1080 | // Linearization data |
| 1080 | qpdf_offset_t first_xref_item_offset; // actual value from file | 1081 | qpdf_offset_t first_xref_item_offset; // actual value from file |
libqpdf/QPDF.cc
| @@ -93,6 +93,7 @@ QPDF::QPDF() : | @@ -93,6 +93,7 @@ QPDF::QPDF() : | ||
| 93 | cached_key_generation(0), | 93 | cached_key_generation(0), |
| 94 | pushed_inherited_attributes_to_pages(false), | 94 | pushed_inherited_attributes_to_pages(false), |
| 95 | copied_stream_data_provider(0), | 95 | copied_stream_data_provider(0), |
| 96 | + reconstructed_xref(false), | ||
| 96 | first_xref_item_offset(0), | 97 | first_xref_item_offset(0), |
| 97 | uncompressed_after_compressed(false) | 98 | uncompressed_after_compressed(false) |
| 98 | { | 99 | { |
| @@ -331,6 +332,15 @@ QPDF::setTrailer(QPDFObjectHandle obj) | @@ -331,6 +332,15 @@ QPDF::setTrailer(QPDFObjectHandle obj) | ||
| 331 | void | 332 | void |
| 332 | QPDF::reconstruct_xref(QPDFExc& e) | 333 | QPDF::reconstruct_xref(QPDFExc& e) |
| 333 | { | 334 | { |
| 335 | + if (this->reconstructed_xref) | ||
| 336 | + { | ||
| 337 | + // Avoid xref reconstruction infinite loops | ||
| 338 | + QTC::TC("qpdf", "QPDF caught recursive xref reconstruction"); | ||
| 339 | + throw e; | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + this->reconstructed_xref = true; | ||
| 343 | + | ||
| 334 | PCRE obj_re("^\\s*(\\d+)\\s+(\\d+)\\s+obj\\b"); | 344 | PCRE obj_re("^\\s*(\\d+)\\s+(\\d+)\\s+obj\\b"); |
| 335 | PCRE endobj_re("^\\s*endobj\\b"); | 345 | PCRE endobj_re("^\\s*endobj\\b"); |
| 336 | PCRE trailer_re("^\\s*trailer\\b"); | 346 | PCRE trailer_re("^\\s*trailer\\b"); |
qpdf/qtest/qpdf.test
| @@ -206,7 +206,7 @@ $td->runtest("remove page we don't have", | @@ -206,7 +206,7 @@ $td->runtest("remove page we don't have", | ||
| 206 | show_ntests(); | 206 | show_ntests(); |
| 207 | # ---------- | 207 | # ---------- |
| 208 | $td->notify("--- Miscellaneous Tests ---"); | 208 | $td->notify("--- Miscellaneous Tests ---"); |
| 209 | -$n_tests += 78; | 209 | +$n_tests += 79; |
| 210 | 210 | ||
| 211 | $td->runtest("qpdf version", | 211 | $td->runtest("qpdf version", |
| 212 | {$td->COMMAND => "qpdf --version"}, | 212 | {$td->COMMAND => "qpdf --version"}, |
| @@ -220,6 +220,7 @@ $td->runtest("C API: qpdf version", | @@ -220,6 +220,7 @@ $td->runtest("C API: qpdf version", | ||
| 220 | 220 | ||
| 221 | # Files to reproduce various bugs | 221 | # Files to reproduce various bugs |
| 222 | foreach my $d ( | 222 | foreach my $d ( |
| 223 | + ["100","xref reconstruction loop"], | ||
| 223 | ["101", "resolve for exception text"], | 224 | ["101", "resolve for exception text"], |
| 224 | ) | 225 | ) |
| 225 | { | 226 | { |
qpdf/qtest/qpdf/issue-100.out
0 → 100644
| 1 | +WARNING: issue-100.pdf: file is damaged | ||
| 2 | +WARNING: issue-100.pdf (file position 736): xref not found | ||
| 3 | +WARNING: issue-100.pdf: Attempting to reconstruct cross-reference table | ||
| 4 | +WARNING: issue-100.pdf (object 5 0, file position 489): attempting to recover stream length | ||
| 5 | +issue-100.pdf (object 6 0, file position 59): expected n n obj |
qpdf/qtest/qpdf/issue-100.pdf
0 → 100644
No preview for this file type