2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-04 03:10:52 +00:00

Avoid xref reconstruction infinite loop (fixes #100)

This is CVE-2017-9209.
This commit is contained in:
Jay Berkenbilt 2017-07-25 10:21:27 -04:00
parent 603f222365
commit 315092dd98
6 changed files with 22 additions and 1 deletions

View File

@ -1,5 +1,9 @@
2017-07-26 Jay Berkenbilt <ejb@ql.org> 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 * CVE-2017-9210: Fix infinite loop caused by attempting to unparse
an object for inclusion in the text of an exception. an object for inclusion in the text of an exception.

View File

@ -1075,6 +1075,7 @@ class QPDF
// copied_stream_data_provider is owned by copied_streams // copied_stream_data_provider is owned by copied_streams
CopiedStreamDataProvider* copied_stream_data_provider; CopiedStreamDataProvider* copied_stream_data_provider;
std::set<QPDFObjGen> attachment_streams; std::set<QPDFObjGen> attachment_streams;
bool reconstructed_xref;
// Linearization data // Linearization data
qpdf_offset_t first_xref_item_offset; // actual value from file qpdf_offset_t first_xref_item_offset; // actual value from file

View File

@ -93,6 +93,7 @@ QPDF::QPDF() :
cached_key_generation(0), cached_key_generation(0),
pushed_inherited_attributes_to_pages(false), pushed_inherited_attributes_to_pages(false),
copied_stream_data_provider(0), copied_stream_data_provider(0),
reconstructed_xref(false),
first_xref_item_offset(0), first_xref_item_offset(0),
uncompressed_after_compressed(false) uncompressed_after_compressed(false)
{ {
@ -331,6 +332,15 @@ QPDF::setTrailer(QPDFObjectHandle obj)
void void
QPDF::reconstruct_xref(QPDFExc& e) 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 obj_re("^\\s*(\\d+)\\s+(\\d+)\\s+obj\\b");
PCRE endobj_re("^\\s*endobj\\b"); PCRE endobj_re("^\\s*endobj\\b");
PCRE trailer_re("^\\s*trailer\\b"); PCRE trailer_re("^\\s*trailer\\b");

View File

@ -206,7 +206,7 @@ $td->runtest("remove page we don't have",
show_ntests(); show_ntests();
# ---------- # ----------
$td->notify("--- Miscellaneous Tests ---"); $td->notify("--- Miscellaneous Tests ---");
$n_tests += 78; $n_tests += 79;
$td->runtest("qpdf version", $td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"}, {$td->COMMAND => "qpdf --version"},
@ -220,6 +220,7 @@ $td->runtest("C API: qpdf version",
# Files to reproduce various bugs # Files to reproduce various bugs
foreach my $d ( foreach my $d (
["100","xref reconstruction loop"],
["101", "resolve for exception text"], ["101", "resolve for exception text"],
) )
{ {

View File

@ -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

Binary file not shown.