diff --git a/ChangeLog b/ChangeLog index 72cef333..c049bc3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2015-02-21 Jay Berkenbilt + + * Ensure that arguments to "R" when parsing the file are direct + objects before trying to resolve them. This prevents specially + crafted files from causing qpdf to crash with a stack overflow. + Thanks to Gynvael Coldwind and Mateusz Jurczyk of the Google + Security Team for providing a sample file with this problem. + 2014-12-01 Jay Berkenbilt * Some broken PDF files lack the required /Type key for /Page and diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index eec4fae3..64a4e3c3 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -966,7 +966,9 @@ QPDFObjectHandle::parseInternal(PointerHolder input, std::string const& value = token.getValue(); if ((value == "R") && (in_array || in_dictionary) && (olist.size() >= 2) && + (! olist.at(olist.size() - 1).isIndirect()) && (olist.at(olist.size() - 1).isInteger()) && + (! olist.at(olist.size() - 2).isIndirect()) && (olist.at(olist.size() - 2).isInteger())) { if (context == 0) diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 3bd1a2fa..75726ca4 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -199,7 +199,7 @@ $td->runtest("remove page we don't have", show_ntests(); # ---------- $td->notify("--- Miscellaneous Tests ---"); -$n_tests += 74; +$n_tests += 75; $td->runtest("qpdf version", {$td->COMMAND => "qpdf --version"}, @@ -562,6 +562,10 @@ $td->runtest("no type key for page nodes", {$td->COMMAND => "qpdf --check no-pages-types.pdf"}, {$td->FILE => "no-pages-types.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); +$td->runtest("ensure arguments to R are direct", + {$td->COMMAND => "qpdf --check indirect-r-arg.pdf"}, + {$td->FILE => "indirect-r-arg.out", $td->EXIT_STATUS => 2}, + $td->NORMALIZE_NEWLINES); show_ntests(); # ---------- diff --git a/qpdf/qtest/qpdf/indirect-r-arg.out b/qpdf/qtest/qpdf/indirect-r-arg.out new file mode 100644 index 00000000..e065ec16 --- /dev/null +++ b/qpdf/qtest/qpdf/indirect-r-arg.out @@ -0,0 +1 @@ +indirect-r-arg.pdf (file position 76): unknown token while reading object (R) diff --git a/qpdf/qtest/qpdf/indirect-r-arg.pdf b/qpdf/qtest/qpdf/indirect-r-arg.pdf new file mode 100644 index 00000000..2a6d18e2 --- /dev/null +++ b/qpdf/qtest/qpdf/indirect-r-arg.pdf @@ -0,0 +1,102 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +%% Original object ID: 1 0 +1 0 obj +<< + /X 1 0 R 0 R + /Pages 2 0 R + /Type /Catalog +>> +endobj + +%% Original object ID: 2 0 +2 0 obj +<< + /Count 1 + /Kids [ + 3 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +%% Original object ID: 3 0 +3 0 obj +<< + /Contents 4 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 6 0 R + >> + /ProcSet 7 0 R + >> + /Type /Page +>> +endobj + +%% Contents for page 1 +%% Original object ID: 4 0 +4 0 obj +<< + /Length 5 0 R +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +5 0 obj +44 +endobj + +%% Original object ID: 6 0 +6 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +%% Original object ID: 5 0 +7 0 obj +[ + /PDF + /Text +] +endobj + +xref +0 8 +0000000000 65535 f +0000000052 00000 n +0000000148 00000 n +0000000257 00000 n +0000000499 00000 n +0000000598 00000 n +0000000644 00000 n +0000000789 00000 n +trailer << + /Root 1 0 R + /Size 8 + /ID [<9e2756c6254602d0b896148e97ee7414><9e2756c6254602d0b896148e97ee7414>] +>> +startxref +824 +%%EOF